回答:
サブクラス化する必要があり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*/);
}
}
}
次に、ViewPager
おそらくとして指定した通常のの代わりに、このクラスを使用してくださいandroid.support.v4.view.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
0 dpです。
そして、setMyScroller();
方法はスムーズな移行のためのものです
0dp
さ/ 1
重量ソリューションを選択した理由は何match_parent
ですか?そうすることでパフォーマンスが向上しますか?
executeKeyEvent()
です。これは、次に呼び出すメソッドですallowScroll()
。 // Never allow swiping by keyboard LEFT, RIGHT, TAB and SHIFT+TAB keys
@Override public boolean executeKeyEvent(KeyEvent event) { return false; }
のより一般的な拡張は、ページングをオンザフライで有効化および無効化できるようにメソッドViewPager
を作成するSetPagingEnabled
ことです。スワイプを有効または無効にするには、2つのメソッドをオーバーライドonTouchEvent
しonInterceptTouchEvent
ます。ページングが無効になっている場合、どちらも「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
、ユーザーはページを移動するためにスワイプできなくなります。
onTouchEvent
とonInterceptTouchEvent
してメソッドをreturn enabled && super.onTouchEvent(event);
最も簡単な方法は、setOnTouchListener
に戻り、に戻ることtrue
ですViewPager
。
mPager.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
return true;
}
});
pager.setCurrentItem(pager.getCurrentItem());
戻る前に追加すると機能しますtrue
。
public int getItemPosition(Object object) { return POSITION_NONE; }
アダプターにあるレイアウトの不具合を解決するには、ページの再作成を強制し、おそらく他の問題も解決します。
スタイル可能として宣言する方が良いので、そのプロパティを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プロパティを持つことができます。
別のViewPager内にViewPager自体がある場合は、オーバーライドのみonTouchEvent
でonInterceptTouchEvent
十分ではありません。子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);
}
}
これで、カスタムを作成する必要はありません ViewPager
ViewPager2
Androidで利用可能な新しい名前ビュー
ViewPager2
従来の水平ページングに加えて垂直ページングをサポートします。属性をViewPager2
設定することにより、要素の垂直ページングを有効にすることができandroid:orientation
ますXMLの使用
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />
コードを使用する
使用中のスワイプを無効にするにviewpager2
は
viewPager2.setUserInputEnabled(false);
viewpager2
使用中のスワイプを有効にするには
viewPager2.setUserInputEnabled(true);
詳細については、こちらを確認してください
確認してください:ViewPagerからViewPager2に移行します
完全な例については、AndroidでのViewPager2の使用を確認してください
viewpager2
しましたRecyclerView.Adapter
ViewPagerから拡張する場合は、前に@araksで示したようにオーバーライドする必要もあります。executeKeyEvent
@Override
public boolean executeKeyEvent(KeyEvent event)
{
return isPagingEnabled ? super.executeKeyEvent(event) : false;
}
Galaxy Tab 4 10 'のような一部のデバイスでは、ほとんどのデバイスでは表示されないこれらのボタンが表示されます。
スワイプを無効にするには
mViewPager.beginFakeDrag();
スワイプを有効にするには
mViewPager.endFakeDrag();
特定の1ページでスワイプを無効にし、ラバーバンドのアニメーションを表示する必要がありました。その方法は次のとおりです。
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);
}
}
onPageSelected
が実行されます。次のページでも切り替わります。したがって、このコードは必要ありません。
私はこれを投稿するのがとても遅いことを知っていますが、これはあなたの結果を達成するための小さなハックです;)
ビューページャーの下にダミービューを追加するだけです。
<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
}
});
レイアウト、配置、動作を少し工夫すれば、想像したことをすべて実行する方法を見つけることができます。
幸運を!
setClickable
はsetOnClickListener
、の代わりに使用することですonClick
。
私は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
、逆に。
私はこれを自分のプロジェクトで使用していますが、今まではうまくいきます。
私はこのクラスを成功させました。一部のデバイスで矢印を使用したスワイプを回避するため、またはアクセシビリティのために、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" />
performClick()
は、メソッドがオーバーライドされないことを警告します。
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
}
}
onInterceptTouchEvent()
すると、子ビューが入力を受け取ることができなくなります。ほとんどの場合、これは意図された動作ではありません。
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
onInterceptTouchEvent()
すると、子ビューが入力を受け取ることができなくなります。ほとんどの場合、これは意図された動作ではありません。
super.onInterceptTouchEvent(event)
これらのビューで結果を呼び出さないと、入力を受け取りません(これはonInterceptTouchEvent
メソッドの文書化された目的です)。
onInterceptTouchEvent()
メソッドをオーバーライドすると、コンテンツ(コンテンツ)が入力を受け取ることができないという事実に対処しています。
onInterceptTouchEvent()および/またはonTouchEvent()のいずれかからオーバーライドしてtrueを返します。これにより、ページャーのタッチイベントが消費されます。
true
タッチイベントが処理されたことを意味するために、彼は戻りたくないのですか?
特定のページ(この例では2ページ目)でスワイプを無効にする別の簡単なソリューション:
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;
}
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;
}
});
ズームとパンをサポートするImageView
sとViewPager
を使用してイメージギャラリーを作成する場合は、Phimpme Android (およびGithubサンプル-PhotoView)のデフォルトのViewPagerを拡張してズーム可能なImageViewを実装する、ここで説明する簡単なソリューションを参照してください。このソリューションは、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;
}
}
}
ViewPager2を使用している場合は、以下を使用する必要があります。
viewpager.setUserInputEnabled(false);
ドキュメントから:
ユーザーが開始したスクロールを有効または無効にします。これには、タッチ入力(スクロールおよびフリングジェスチャー)とアクセシビリティ入力が含まれます。キーボード入力の無効化はまだサポートされていません。ユーザーが開始したスクロールが無効になっている場合でも、プログラムによるsetCurrentItemのスクロールは機能します。デフォルトでは、ユーザーが開始したスクロールは有効になっています。
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>
上記のコードはどれもスムーズに機能していません。
<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>
これが私の実装
です。スワイプアニメーションを無効にしたい場合は、swipeListenerを左右に使用し、指なしでスクロールできますが、アニメーションは必要ありません。
1-オーバーライドViewpager
メソッドonInterceptTouchEvent
とonTouchEvent
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);
}
...
}
ビューページャーを少しカスタマイズして、スワイプを簡単に無効にしました。
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);
}
}
shareViewPager?.setOnTouchListener(object :View.OnTouchListener{
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
for (PAGE in 0..shareViewPager.adapter!!.count){
if (shareViewPager.currentItem==PAGE){
shareViewPager.setCurrentItem(PAGE-1,false)
shareViewPager.setCurrentItem(PAGE,false)
}}
return true
}
})