ViewPagerがあり、その下には10個のボタンがあります。 #4などのボタンをクリックすると、ポケットベルはmPager.setCurrentItem(3);
によってすぐに4ページに移動します。しかし、私は水平方向に指でスワイプしてページングを無効にしたいです。このように、ページングはボタンをクリックすることによって行われますONLY。それで、どのように私は指でスワイプを無効にすることができますか?
ViewPager
をサブクラス化する必要があります。 onTouchEvent
にはたくさんの良いことがありますので、子のビューに触れることを許可するように変更したくはありません。 onInterceptTouchEvent
はあなたが変更したいものです。 ViewPager
のコードを見ると、コメントが表示されます。
/*
* This method JUST determines whether we want to intercept the motion.
* If we return true, onMotionEvent will be called and we do the actual
* scrolling there.
*/
これが完全な解決策です:
まず、このクラスをsrc
フォルダに追加します。
import Android.content.Context;
import Android.support.v4.view.ViewPager;
import Android.util.AttributeSet;
import Android.view.MotionEvent;
import Android.view.animation.DecelerateInterpolator;
import Android.widget.Scroller;
import Java.lang.reflect.Field;
public class NonSwipeableViewPager extends ViewPager {
public NonSwipeableViewPager(Context context) {
super(context);
setMyScroller();
}
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setMyScroller();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
//down one is added for smooth scrolling
private void setMyScroller() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
scroller.set(this, new MyScroller(getContext()));
} catch (Exception e) {
e.printStackTrace();
}
}
public class MyScroller extends Scroller {
public MyScroller(Context context) {
super(context, new DecelerateInterpolator());
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
}
}
}
次に、通常はAndroid.support.v4.view.ViewPager
として指定した通常のViewPager
の代わりにこのクラスを必ず使用してください。レイアウトファイルでは、次のように指定します。
<com.yourcompany.NonSwipeableViewPager
Android:id="@+id/view_pager"
Android:layout_width="match_parent"
Android:layout_height="0dp"
Android:layout_weight="1" />
この例はLinearLayout
内にあり、画面全体を占めることを意図しています。そのため、layout_weight
が1でlayout_height
が0dpです。
そしてsetMyScroller();
メソッドはスムーズな移行のためのものです
ViewPager
のより一般的な拡張は、その場でページングを有効または無効にできるようにSetPagingEnabled
メソッドを作成することです。スワイプを有効/無効にするには、onTouchEvent
とonInterceptTouchEvent
の2つのメソッドをオーバーライドするだけです。ページングが無効になっている場合、両方とも "false"を返します。
public class CustomViewPager extends ViewPager {
private boolean enabled;
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.enabled = true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onTouchEvent(event);
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onInterceptTouchEvent(event);
}
return false;
}
public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}
}
次に、XMLのビルトインビューページャの代わりにこれを選択してください。
<mypackage.CustomViewPager
Android:id="@+id/myViewPager"
Android:layout_height="match_parent"
Android:layout_width="match_parent" />
setPagingEnabled
メソッドをfalse
と一緒に呼び出すだけで、ユーザーはページ番号までスワイプすることはできません。
最も簡単な方法は、setOnTouchListener
を返し、true
に対してViewPager
を返すことです。
mPager.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
return true;
}
});
それをスタイル可能と宣言したほうがよいので、そのプロパティをxmlから変更できます。
private boolean swipeable;
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyViewPager);
try {
swipeable = a.getBoolean(R.styleable.MyViewPager_swipeable, true);
} finally {
a.recycle();
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return swipeable ? super.onInterceptTouchEvent(event) : false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return swipeable ? super.onTouchEvent(event) : false;
}
そしてあなたのvalues/attr.xmlで:
<declare-styleable name="MyViewPager">
<attr name="swipeable" format="boolean" />
</declare-styleable>
あなたがあなたのレイアウトxmlでそれを使うことができるように:
<mypackage.MyViewPager
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/viewPager"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
app:swipeable="false" />
もちろん、あなたはまだget/setプロパティを持つことができます。
onTouchEvent
とonInterceptTouchEvent
だけをオーバーライドしても、ViewPager自体が別のViewPagerの中にある場合は十分ではありません。最初のページまたは最後のページに配置されていない限り、子ViewPagerは親ViewPagerから水平スクロールタッチイベントを取得します。
この設定を正しく機能させるためには、canScrollHorizontally
メソッドもオーバーライドする必要があります。
下記のLockableViewPager
の実装を見てください。
public class LockableViewPager extends ViewPager {
private boolean swipeLocked;
public LockableViewPager(Context context) {
super(context);
}
public LockableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean getSwipeLocked() {
return swipeLocked;
}
public void setSwipeLocked(boolean swipeLocked) {
this.swipeLocked = swipeLocked;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return !swipeLocked && super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return !swipeLocked && super.onInterceptTouchEvent(event);
}
@Override
public boolean canScrollHorizontally(int direction) {
return !swipeLocked && super.canScrollHorizontally(direction);
}
}
スワイプを無効にする
mViewPager.beginFakeDrag();
スワイプを有効にする
mViewPager.endFakeDrag();
ある特定のページでスワイプを無効にして、素敵な輪ゴムのアニメーションにする必要があります。
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
if (position == MANDATORY_PAGE_LOCATION && positionOffset > 0.5) {
mViewPager.setCurrentItem(MANDATORY_PAGE_LOCATION, true);
}
}
私はスワイプコントロールでCustomViewPager
を書きました:
public class ScrollableViewPager extends ViewPager {
private boolean canScroll = true;
public ScrollableViewPager(Context context) {
super(context);
}
public ScrollableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setCanScroll(boolean canScroll) {
this.canScroll = canScroll;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return canScroll && super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return canScroll && super.onInterceptTouchEvent(ev);
}
}
canScroll
をtrue
に設定した場合、このViewPager
は指でスワイプすることができます。逆にfalse
。
私は自分のプロジェクトでこれを使っていますが、今までそれはうまく機能します。
私はこれを投稿するのが遅すぎることを知っていますが、ここにあなたの結果を達成するための小さなハックがあります;)
単純にダミービューを追加してください below あなたのviewpager:
<Android.support.v4.view.ViewPager
Android:layout_width="match_parent"
Android:layout_height="match_parent">
</Android.support.v4.view.ViewPager>
<RelativeLayout
Android:id="@+id/dummyView"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
</RelativeLayout>
それからOnClickListener
をあなたのRelativeLayout
に追加してください。
dummyView = (RelativeLayout) findViewById(R.id.dummyView);
dummyView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Just leave this empty
}
});
レイアウト、配置、振る舞いについて少しクリエイティブになりましょう。あなたが想像していることをすべてやる方法を見つけることを学ぶでしょう:)
がんばろう!
onInterceptTouchEvent() または /onTouchEvent() のいずれかからオーバーライドしてtrueを返すようにしてください。これらはページャのタッチイベントを消費します。
私はこのクラスをうまく使いました。 executeKeyEvent をオーバーライドすることは、一部のデバイスでは矢印を使ったスワイプを避けるため、またはアクセシビリティのために必要です。
import Android.content.Context;
import Android.support.v4.view.ViewPager;
import Android.util.AttributeSet;
import Android.view.KeyEvent;
import Android.view.MotionEvent;
public class ViewPagerNoSwipe extends ViewPager {
/**
* Is swipe enabled
*/
private boolean enabled;
public ViewPagerNoSwipe(Context context, AttributeSet attrs) {
super(context, attrs);
this.enabled = false; // By default swiping is disabled
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.enabled ? super.onTouchEvent(event) : false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return this.enabled ? super.onInterceptTouchEvent(event) : false;
}
@Override
public boolean executeKeyEvent(KeyEvent event) {
return this.enabled ? super.executeKeyEvent(event) : false;
}
public void setSwipeEnabled(boolean enabled) {
this.enabled = enabled;
}
}
そして xml の中でこれを次のように呼びます。
<package.path.ViewPagerNoSwipe
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
Kotlinでは、ViewPagerクラスを継承するカスタムウィジェットを作成し、スワイプ動作を制御するためのフラグ値を追加することでこれを解決できます。
NoSwipePager.kt
class NoSwipePager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) {
var pagingEnabled: Boolean = false
override fun onTouchEvent(event: MotionEvent): Boolean {
return if (this.pagingEnabled) {
super.onTouchEvent(event)
} else false
}
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return if (this.pagingEnabled) {
super.onInterceptTouchEvent(event)
} else false
}
}
XMLで
<your.package.NoSwipePager
Android:id="@+id/view_pager"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_below="@id/tab_layout" />
プログラムでスワイプを無効にします。 kotlin-Android-extensions
プラグインがbuild.gradleに適用されている場合、以下のコードを記述することでスワイプを無効にできます。
view_pager.pagingEnabled = false
それ以外の場合は、以下のコードを使用してスワイプを無効にできます。
val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false
今、私たちはカスタムViewPager
を作成する必要はありません。
新しい ViewPager2
name Androidで表示可能
viewpager2
でスワイプを無効にするには
viewPager2.setUserInputEnabled(false);
viewpager2
でスワイプを有効にするには
viewPager2.setUserInputEnabled(true);
詳しくはこちらをご覧ください
ズームとパンをサポートするImageView
sおよびViewPager
を使用して画像ギャラリーを作成する場合は、ここで説明する簡単な解決策を参照してください。 Phimpme Android (および Githubサンプル-PhotoView )このソリューションは、ViewPager
だけでは機能しません。
public class CustomViewPager extends ViewPager {
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs)
{
super(context,attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
try {
return super.onInterceptTouchEvent(event);
} catch (IllegalArgumentException e) {
return false;
}
}
}
特定のページ(この例では2ページ目)でスワイプを無効にするもう1つの簡単な解決策:
int PAGE = 2;
viewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (viewPager.getCurrentItem() == PAGE) {
viewPager.setCurrentItem(PAGE-1, false);
viewPager.setCurrentItem(PAGE, false);
return true;
}
return false;
}
XamarinでAndroidにも同じように実装したい場合は、C#への翻訳です。
属性に「 ScrollEnabled 」という名前を付けました。 iOSは単にexcatと同じ名前を使っているからです。そのため、両方のプラットフォームで同じ名前を付けることで、開発者にとって簡単になります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Android.Util;
namespace YourNameSpace.ViewPackage {
// Need to disable swiping for ViewPager, if user performs Pre DSA and the dsa is not completed yet
// http://stackoverflow.com/questions/9650265/how-do-disable-paging-by-swiping-with-finger-in-viewpager-but-still-be-able-to-s
public class CustomViewPager: ViewPager {
public bool ScrollEnabled;
public CustomViewPager(Context context, IAttributeSet attrs) : base(context, attrs) {
this.ScrollEnabled = true;
}
public override bool OnTouchEvent(MotionEvent e) {
if (this.ScrollEnabled) {
return base.OnTouchEvent(e);
}
return false;
}
public override bool OnInterceptTouchEvent(MotionEvent e) {
if (this.ScrollEnabled) {
return base.OnInterceptTouchEvent(e);
}
return false;
}
// For ViewPager inside another ViewPager
public override bool CanScrollHorizontally(int direction) {
return this.ScrollEnabled && base.CanScrollHorizontally(direction);
}
// Some devices like the Galaxy Tab 4 10' show swipe buttons where most devices never show them
// So, you could still swipe through the ViewPager with your keyboard keys
public override bool ExecuteKeyEvent(KeyEvent evt) {
return this.ScrollEnabled ? base.ExecuteKeyEvent(evt) : false;
}
}
}
.axmlファイルの場合:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<YourNameSpace.ViewPackage.CustomViewPager
Android:id="@+id/pager"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="@Android:color/white"
Android:layout_alignParentTop="true" />
</LinearLayout>
ビューページャを少しカスタマイズして、スワイプを簡単に無効にしました。
public class CustomViewPager extends ViewPager {
private boolean swipeLocked;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean getSwipeLocked() {
return swipeLocked;
}
public void setSwipeLocked(boolean swipeLocked) {
this.swipeLocked = swipeLocked;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return !swipeLocked && super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return !swipeLocked && super.onInterceptTouchEvent(event);
}
@Override
public boolean canScrollHorizontally(int direction) {
return !swipeLocked && super.canScrollHorizontally(direction);
}
}
これが私の実装です
スワイプアニメーションを無効にしたい場合は、swipeListenerを左右に使用しても、指なしではなくアニメーションなしでスクロールすることができます。
Viewpager
メソッドonInterceptTouchEvent
およびonTouchEvent
を1 - オーバーライドする
2-あなた自身のGestureDetector
を作成します
3 - スワイプジェスチャーを検出してsetCurrentItem(item, false)
を使う
ViewPager
public class ViewPagerNoSwipe extends ViewPager {
private final GestureDetector gestureDetector;
private OnSwipeListener mOnSwipeListener;
public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
mOnSwipeListener = onSwipeListener;
}
public ViewPagerNoSwipe(@NonNull Context context) {
super(context);
gestureDetector = new GestureDetector(context, new GestureListener());
}
public ViewPagerNoSwipe(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
gestureDetector = new GestureDetector(context, new GestureListener());
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
gestureDetector.onTouchEvent(ev);
return false;
}
public class GestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
if(mOnSwipeListener!=null)
mOnSwipeListener.onSwipeRight();
} else {
if(mOnSwipeListener!=null)
mOnSwipeListener.onSwipeLeft();
}
result = true;
}
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
if(mOnSwipeListener!=null)
mOnSwipeListener.onSwipeBottom();
} else {
if(mOnSwipeListener!=null)
mOnSwipeListener.onSwipeTop();
}
result = true;
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
public interface OnSwipeListener {
void onSwipeRight();
void onSwipeLeft();
void onSwipeTop();
void onSwipeBottom();
}
}
viewPagerを設定したときにswipeListenerを設定します。
postsPager.setOnSwipeListener(new ViewPagerNoSwipe.OnSwipeListener() {
@Override
public void onSwipeRight() {
postsPager.setCurrentItem(postsPager.getCurrentItem() + 1,false);
}
@Override
public void onSwipeLeft() {
postsPager.setCurrentItem(postsPager.getCurrentItem() - 1, false);
}
...
}
Kotlinで、私の解決策は、上記の答えを組み合わせたものです。
class CustomViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
var swipeEnabled = false
override fun onTouchEvent(ev: MotionEvent?): Boolean {
return if (swipeEnabled) super.onTouchEvent(ev) else false
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return if (swipeEnabled) super.onInterceptTouchEvent(ev) else false
}
override fun executeKeyEvent(event: KeyEvent): Boolean {
return if (swipeEnabled) super.executeKeyEvent(event) else false
}
}
This worked for me
viewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (viewPager.getCurrentItem() == 0) {
viewPager.setCurrentItem(-1, false);
return true;
}
else if (viewPager.getCurrentItem() == 1) {
viewPager.setCurrentItem(1, false);
return true;
}
else if (viewPager.getCurrentItem() == 2) {
viewPager.setCurrentItem(2, false);
return true;
}
return true;
}
});
上記のコードのどれも円滑に働いていません。私はこれを試しました
<HorizontalScrollView
Android:id="@+id/horizontalScrollView"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fillViewport="true">
<Android.support.v4.view.ViewPager
Android:id="@+id/pager"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</HorizontalScrollView>