我正在使用castorflex / VerticalViewPager库,里面包含ListView的片段。问题是,当我开始滑动ListView元素时,我无法更改ViewPager的页面。当ListView到达ViewPager列表的顶部/底部时,有没有办法传递触摸事件?我不想达到平滑的效果(当列表不能再滚动时,ViewPager开始滚动,所有在一个触摸事件中)
答案 0 :(得分:0)
这是我实施的垂直寻呼机类的解决方案here
而不是RecyclerView实现扩展它的自定义类,并在我们的自定义RecyclerView类覆盖中
public boolean onTouchEvent(MotionEvent event)
在这里,我们可以将MotionEvent event
传递给类似下面的类,以确定是否应该拦截事件:
/**
* Tests the MotionEvent for valid behavior to care about overriding the touch event with
*/
private boolean shouldDisableScrollableParent(final MotionEvent event) {
boolean intercept = false;
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
// Here you can try to detect the swipe. It will be necessary to
// store more than the previous value to check that the user move constantly in the same direction
intercept = detectSwipe(dx, dy);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
default:
break;
}
mPreviousX = x;
mPreviousY = y;
return intercept;
}
/**
* Tests if we want to disable the parent touch interception
*/
private boolean detectSwipe(final float dx, final float dy) {
// True if we're scrolling in Y direction
if (Math.abs(dx) < Math.abs(dy)) {
FoundationLog.d(TAG, "Direction Y is yielding: " + dy);
if (dy < 0) {
// Touch from lower to higher
return true;
}
// Top view isn't shown, can always scroll up
final View view = getChildAt(0);
if (view == null) {
return true;
}
// Top view baseline doesn't equal to top of the RecyclerView
if (view.getTop() < 0) {
return true;
}
}
return false;
}
然后在自定义RecyclerView类的public boolean onTouchEvent(MotionEvent event)
方法中,检查getParent()
(并且可能迭代地向根父级)解析是否解析为ViewParent
的类。查看您要覆盖的触摸。如果是,请在requestDisallowInterceptTouchEvent()
true
设置为ViewParent
答案 1 :(得分:0)
这是一个迟到的回复,但我最近被要求将我们的应用程序ViewPager更改为垂直,我的列表内部存在完全相同的问题。我希望这可以帮助其他可能遇到同样问题的人。
首先,我的Fragment是ListFragment的扩展,但它对于任何包含列表的Fragment(显然有轻微修改)的工作方式相同。首先,我在我的列表上设置了OnScrollListener,在onScrollStateChanged中我有一个方法updateListVisibility,如果列表的顶部或底部的顶部在列表中可见(updateListPositionVisibility),则返回我的Activity更新。
public class MyListFragment extends ListFragment {
.....
private OnScrollStateChangedListener mListener;
.....
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
......
getListView().setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
updateListVisibility();
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
}
public void updateListVisibility() {
if (getListView() != null && getListView().getChildCount() > 0) {
boolean firstItemVisible = getListView().getFirstVisiblePosition() == 0;
boolean topOfFirstItemVisible = getListView().getChildAt(0).getTop() == 0;
boolean lastItemVisible = getListView().getLastVisiblePosition() == getListView().getAdapter().getCount() - 1;
boolean bottomOfLastItemVisible = getListView().getChildAt(getListView().getChildCount() - 1).getBottom() <= getListView().getHeight();
mListener.updateListPositionVisibility(firstItemVisible && topOfFirstItemVisible, lastItemVisible && bottomOfLastItemVisible);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnScrollStateChangedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnScrollStateChangedListener");
}
}
/**
* Container Activity must implement this interface....
*/
public interface OnScrollStateChangedListener {
public void updateListPositionVisibility(boolean topIsVisible, boolean bottomIsVisible);
}
.....
}
在我的活动中,我在ViewPager上设置了OnPageChangeListener,在onPageSelected中我使用我的适配器来获取Fragment,以便我可以在其上调用updateListVisibility,然后调用回我的活动。我的回调实现使用列表顶部和底部的可见性状态更新了ViewPager(请参阅setListViewPositionsInViewPager)。
public class VerticallyPagedActivity extends BaseFragmentActivity implements
MyListFragment.OnScrollStateChangedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
......
mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
Object fragment = mAdapter.mItems.get(position);
if (fragment instanceof MyListFragment) {
((MyListFragment) fragment).updateListVisibility();
} else {
setListViewPositionsInViewPager(false, false);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
public void setListViewPositionsInViewPager(boolean handleEventTop, boolean handleEventBottom) {
mPager.setListVisibility(handleEventTop, handleEventBottom);
}
// Callback.
@Override
public void updateListPositionVisibility(boolean topIsVisible, boolean bottomIsVisible) {
setListViewPositionsInViewPager(topIsVisible, bottomIsVisible);
}
我的适配器只是在mItems中维护一个片段的实例。
public class MyAdapter extends FragmentStatePagerAdapter {
.....
public Map<Integer, Fragment> mItems;
public MyAdapter(FragmentManager fm, List<Content> content) {
super(fm);
mItems = new HashMap<>();
.....
@Override
public Fragment getItem(int position) {
.....
MyListFragment fragment = new MyListFragment();
.....
mItems.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
mItems.remove(position);
super.destroyItem(container, position, object);
}
}
然后在我的Castorflex垂直视图分页器中,我使用名为setListVisibility的方法设置列表可见性值。每次滚动列表或查看ViewPager时都会更新这些内容,这意味着它们始终是最新的。然后,当顶部可见并且用户试图上升或底部可见并且用户试图关闭时,寻呼机最重要的部分是拦截事件。使用在MotionEvent.ACTION_MOVE下的switch语句内计算的dy值可以轻松实现这一点。
public class VerticalPager extends ViewGroup {
.....
private boolean topOfListIsVisible;
private boolean bottomOfListIsVisible;
public void setListVisibility(boolean pTop, boolean pBottom) {
topOfListIsVisible = pTop;
bottomOfListIsVisible = pBottom;
}
.....
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
......
switch (action) {
case MotionEvent.ACTION_MOVE: {
......
final float y = MotionEventCompat.getY(ev, pointerIndex);
final float dy = y - mLastMotionY;
final float yDiff = Math.abs(dy);
......
// Pager needs to handle the event.
if (topOfListIsVisible && bottomOfListIsVisible || bottomOfListIsVisible && dy < 0 || topOfListIsVisible && dy > 0) {
return true;
}
}
.....
}
.....
}