Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。
Posted 星辰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。相关的知识,希望对你有一定的参考价值。
最近项目要实现ScrollView中嵌套广告轮播图+RecyleView卡片布局,并且RecyleView按照header和内容的排列样式,因为RecyleView的可扩展性很强,所以我毫无疑问的选择了它,而且让RecyleView实现了可拖拽的效果,
最后我再加上了下拉刷新的效果(这里我用的下拉刷新控件是三方的SmartRefreshLayout)。记得刚开始实现这个效果的时候还是十分的得心印手。可是当我测试的时候,发现RecyleView的子item的拖拽效果并不流畅,起初我以
为是由于RecyleView和ScrollView的滑动冲突导致的,可是慢慢我自己重新写了个demo,逐步调试,发现肯定是下拉刷新控件和ScrollView的原因造成的,于是对症下药,终于找到了解决的办法,这里将我的答案记录下来,为了
后面其他的人遇到和我一样的问题,避免他们走很多的弯路,希望会对他们有所帮助,当然把自己遇到问题和解决问题的办法都记录下来,这对自己来说也是一种成长。如果有其他更好的思路,希望给我留言,谢谢。
解决办法一:
在布局页面中把ScrollView控件换成NestedScrollView控件:
对NestedScrollView的详解:http://www.cnblogs.com/skytwo/p/4613912.html
<android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> .............. </android.support.v4.widget.NestedScrollView>
以下是简单demo:
MainActivity:用底部BottomNavigationBar,实现viewpager和fragment连用
代码:
public class MainActivity extends AppCompatActivity implements BottomNavigationBar.OnTabSelectedListener,ViewPager.OnPageChangeListener{ private ViewPager viewPager; private BottomNavigationBar bottomNavigationBar; //存放fragment的集合 private Fragment[] fragments; //切换不同fragment用的下标 private int index; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initBottomNavigationBar(); initViewPager(); } //初始化底部导航菜单 private void initBottomNavigationBar() { bottomNavigationBar = (BottomNavigationBar) findViewById(R.id.bottom_navigation_bar); bottomNavigationBar.setTabSelectedListener(this); bottomNavigationBar.clearAll(); bottomNavigationBar.setMode(BottomNavigationBar.MODE_FIXED); bottomNavigationBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC); bottomNavigationBar.addItem(new BottomNavigationItem(R.drawable.ic_launcher,"主页").setInactiveIconResource(R.drawable.ic_launcher).setActiveColorResource(R.color.colorPrimaryDark)) .addItem(new BottomNavigationItem(R.drawable.ic_launcher,"单据").setInactiveIconResource(R.drawable.ic_launcher).setActiveColorResource(R.color.colorPrimaryDark)) .addItem(new BottomNavigationItem(R.drawable.ic_launcher, "审核").setInactiveIconResource(R.drawable.ic_launcher).setActiveColorResource(R.color.colorPrimaryDark)) .addItem(new BottomNavigationItem(R.drawable.ic_launcher, "报表").setInactiveIconResource(R.drawable.ic_launcher).setActiveColorResource(R.color.colorPrimaryDark)) .addItem(new BottomNavigationItem(R.drawable.ic_launcher,"设置").setInactiveIconResource(R.drawable.ic_launcher).setActiveColorResource(R.color.colorPrimaryDark)) .initialise(); } //初始化viewpager private void initViewPager() { viewPager = (ViewPager) findViewById(R.id.view_pager); fragments = new Fragment[5]; fragments[0]=new FragOne(); fragments[1]=new FragTwo(); fragments[2]=new FragThree(); fragments[3]=new FragFour(); fragments[4]=new FragFive(); viewPager.setOffscreenPageLimit(4); viewPager.setAdapter(new SectionsPagerAdapter(getSupportFragmentManager(), fragments)); viewPager.addOnPageChangeListener(this); viewPager.setCurrentItem(0); } @Override public void onTabSelected(int position) { viewPager.setCurrentItem(position); } @Override public void onTabUnselected(int position) { } @Override public void onTabReselected(int position) { } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int i) { bottomNavigationBar.selectTab(i); this.index = i; } @Override public void onPageScrollStateChanged(int state) { } class SectionsPagerAdapter extends FragmentPagerAdapter { Fragment fragments[]=new Fragment[4]; public SectionsPagerAdapter(FragmentManager fm, Fragment fragments[]) { super(fm); this.fragments = fragments; } @Override public Fragment getItem(int position) { return fragments[position]; } @Override public int getCount() { return fragments.length; } } }
MainActity布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.admin.demo.MainActivity"> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <com.ashokvarma.bottomnavigation.BottomNavigationBar android:id="@+id/bottom_navigation_bar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" /> </LinearLayout>
主fragment:实现下拉刷新、上拉加载、RecyleView拖拽等各种效果的fragment
public class FragOne extends Fragment implements MyItemTouchCallback.OnDragListener { private List<String> list = new ArrayList<String>(); private View parent; //显示模块的recyleview private RecyclerView mRecyclerView; //可拖动模块的帮助类 private ItemTouchHelper itemTouchHelper; //适配器 private RecyleViewAdapter mRecyclerAdapter; //声明刷新控件 private SmartRefreshLayout srf; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { parent = inflater.inflate(R.layout.frag_one, container, false); initView(); return parent; } private void initView() { for (int i = 0; i < 100; i++) { list.add(i + ""); } mRecyclerView = (RecyclerView) parent.findViewById(recyclerView); // 设置添加删除item的时候的动画效果 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 4); gridLayoutManager.setSmoothScrollbarEnabled(true); gridLayoutManager.setAutoMeasureEnabled(true); mRecyclerView.setLayoutManager(gridLayoutManager); mRecyclerView.setHasFixedSize(true); mRecyclerView.setNestedScrollingEnabled(false); // 设置适配器 mRecyclerAdapter = new RecyleViewAdapter(list); itemTouchHelper = new ItemTouchHelper(new MyItemTouchCallback(mRecyclerAdapter).setOnDragListener(this)); itemTouchHelper.attachToRecyclerView(mRecyclerView); mRecyclerView.setAdapter(mRecyclerAdapter); mRecyclerView.addOnItemTouchListener(new OnRecyclerItemClickListener(mRecyclerView) { @Override public void onLongClick(RecyclerView.ViewHolder vh) { itemTouchHelper.startDrag(vh); VibratorUtil.Vibrate(getActivity(), 70); //震动70ms } @Override public void onItemClick(RecyclerView.ViewHolder vh) { super.onItemClick(vh); } }); srf = (SmartRefreshLayout) parent.findViewById(R.id.refresh); srf.setDefaultRefreshHeaderCreater(new DefaultRefreshHeaderCreater() { @Override public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) { return new ClassicsHeader(context);//指定为经典Header,默认是 贝塞尔雷达Header } }); srf.setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh(RefreshLayout refreshlayout) { srf.postDelayed(new Runnable() { @Override public void run() { mRecyclerAdapter.notifyDataSetChanged(); srf.finishRefresh(); Toast.makeText(getActivity(), "刷新成功", Toast.LENGTH_SHORT).show(); } }, 3000); } }); srf.setEnableLoadmore(false);//屏蔽掉上拉加载的效果 } @Override public void onFinishDrag() { } class RecyleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements MyItemTouchCallback.ItemTouchAdapter { private List<String> mData; public RecyleViewAdapter(List<String> data) { mData = data; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new TestViewHolder(View.inflate(parent.getContext(), R.layout.item_test, null)); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { TestViewHolder tHolder = (TestViewHolder) holder; tHolder.tv.setText(mData.get(position)); } @Override public int getItemCount() { return mData == null ? 0 : mData.size(); } @Override public void onMove(int fromPosition, int toPosition) { if (fromPosition < toPosition) { for (int i = fromPosition; i < toPosition; i++) { Collections.swap(mData, i, i + 1); } } else { for (int i = fromPosition; i > toPosition; i--) { Collections.swap(mData, i, i - 1); } } notifyItemMoved(fromPosition, toPosition); } @Override public void onSwiped(int position) { mData.remove(position); notifyItemRemoved(position); } private class TestViewHolder extends RecyclerView.ViewHolder { TextView tv; public TestViewHolder(View itemView) { super(itemView); tv = (TextView) itemView.findViewById(R.id.tv); } } }
主fragment布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.scwang.smartrefresh.layout.SmartRefreshLayout android:id="@+id/refresh" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/test" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:descendantFocusability="blocksDescendants"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView> </RelativeLayout> </LinearLayout> </android.support.v4.widget.NestedScrollView> </com.scwang.smartrefresh.layout.SmartRefreshLayout> </LinearLayout>
RecyleView实现可拖拽效果的帮助类:
MyItemTouchCallback :
public class MyItemTouchCallback extends ItemTouchHelper.Callback { private ItemTouchAdapter itemTouchAdapter; public MyItemTouchCallback(ItemTouchAdapter itemTouchAdapter){ this.itemTouchAdapter = itemTouchAdapter; } @Override public boolean isLongPressDragEnabled() { return false; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; final int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); } else { final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; final int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); } } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { int fromPosition = viewHolder.getAdapterPosition();//得到拖动ViewHolder的position int toPosition = target.getAdapterPosition();//得到目标ViewHolder的position itemTouchAdapter.onMove(fromPosition,toPosition); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { int position = viewHolder.getAdapterPosition(); itemTouchAdapter.onSwiped(position); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { //滑动时改变Item的透明度 final float alpha = 1 - Math.abs(dX) / (float) viewHolder.itemView.getWidth(); viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } } @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { if (background == null && bkcolor == -1) { Drawable drawable = viewHolder.itemView.getBackground(); if (drawable == null) { bkcolor = 0; } else { background = drawable; } } viewHolder.itemView.setBackgroundColor(Color.LTGRAY); } super.onSelectedChanged(viewHolder, actionState); } @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); viewHolder.itemView.setAlpha(1.0f); if (background != null) viewHolder.itemView.setBackgroundDrawable(background); if (bkcolor != -1) viewHolder.itemView.setBackgroundColor(bkcolor); //viewHolder.itemView.setBackgroundColor(0); if (onDragListener!=null){ onDragListener.onFinishDrag(); } } private Drawable background = null; private int bkcolor = -1; private OnDragListener onDragListener; public MyItemTouchCallback setOnDragListener(OnDragListener onDragListener) { this.onDragListener = onDragListener; return this; } public interface OnDragListener{ void onFinishDrag(); } public interface ItemTouchAdapter { void onMove(int fromPosition, int toPosition); void onSwiped(int position); } }
OnRecyclerItemClickListener:
public class OnRecyclerItemClickListener implements RecyclerView.OnItemTouchListener{ private GestureDetectorCompat mGestureDetector; private RecyclerView recyclerView; public OnRecyclerItemClickListener(RecyclerView recyclerView){ this.recyclerView = recyclerView; mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(),new ItemTouchHelperGestureListener()); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { mGestureDetector.onTouchEvent(e); return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { mGestureDetector.onTouchEvent(e); } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child!=null) { RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child); onItemClick(vh); } return true; } @Override public void onLongPress(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child!=null) { RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child); onLongClick(vh); } } } public void onLongClick(RecyclerView.ViewHolder vh){} public void onItemClick(RecyclerView.ViewHolder vh){} }
VibratorUtil(手机振动工具类)
/** * 手机震动工具类 * @author Administrator * 使用必须添加权限:<uses-permission android:name="android.permission.VIBRATE" /> */ public class VibratorUtil { /** * final Activity activity :调用该方法的Activity实例 * long milliseconds :震动的时长,单位是毫秒 * long[] pattern :自定义震动模式 。数组中数字的含义依次是[静止时长,震动时长,静止时长,震动时长。。。]时长的单位是毫秒 * boolean isRepeat : 是否反复震动,如果是true,反复震动,如果是false,只震动一次 */ public static void Vibrate(final Activity activity, long milliseconds) { Vibrator vib = (Vibrator) activity.getSystemService(Service.VIBRATOR_SERVICE); vib.vibrate(milliseconds); } public static void Vibrate(final Activity activity, long[] pattern, boolean isRepeat) { Vibrator vib = (Vibrator) activity.getSystemService(Service.VIBRATOR_SERVICE); vib.vibrate(pattern, isRepeat ? 1 : -1); } }
以上是关于Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。的主要内容,如果未能解决你的问题,请参考以下文章
Android SwipeRefreshLayout下拉刷新控件源码简单分析
Android 控件smartRefeshLayout只要下拉刷新,禁止上拉加载
Android 比SwipeRefreshLayout更漂亮和强大的下拉刷新控件:Android-MaterialRefreshLayout