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下拉刷新和listview冲突解决方案

Android SwipeRefreshLayout下拉刷新控件源码简单分析

Android 控件smartRefeshLayout只要下拉刷新,禁止上拉加载

Android 比SwipeRefreshLayout更漂亮和强大的下拉刷新控件:Android-MaterialRefreshLayout

Android控件下拉刷新:SwipeRefreshLayout

android官方下拉刷新控件SwipeRefreshLayout的使用