Android学习笔记(四)--RecyclerView扩展下拉刷新与左滑删除

今天在使用QQ的时候就想到制作一个消息列表的类似效果,可以实现下拉刷新和左滑删除效果,于是就抽空试了试。先上效果图。
这里写图片描述
这是正在刷新的时候。然后就会增添一个item(那个刷新的圈是会转的然后还可以变颜色我不会截动图)。见下图。
这里写图片描述
RecyclerView的adpter使用的还是我上篇博客里的那个http://blog.csdn.net/callmesp/article/details/52895630
没有变化。我们先来实现一下下拉刷新效果。
就是在xml文件里面改变了一下,不得不说这种官方提供的空间使用起来简单粗暴。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerview"/>
</android.support.v4.widget.SwipeRefreshLayout>

在最外层嵌套个swipeRefreshLayout,仅此而已是不是很简单。然后在activity里面定义一下就可以了。来看一下主活动中改变的部分吧。

 swipeRefreshLayout=(SwipeRefreshLayout)findViewById(R.id.swipe_container);
        swipeRefreshLayout.setColorSchemeResources(R.color.colorAccent,R.color.colorPrimary,R.color.black,R.color.white);
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                Log.e("0", "正在刷新");
                new Handler().postDelayed(new Runnable(){
                    @Override
                    public void run() {
                        Log.e("0", "刷新完成");
                        recycleAdapter.addData(0);
                        swipeRefreshLayout.setRefreshing(false);
                    }
                }, 2000);
            }
        });

就这么简单就完成了。使用了一个Handler().postDelayed来假装延迟2 second的一个刷新效果,然后用一个在Adapter中的addData来添加一个item模拟出了刷新的效果。下面我们看一下左滑刷新如何实现————-作者先去睡觉明天更。–>滚回来了。。左滑刷新功能是一个平时实用性很强的功能,我的一开始的想法是偷个懒重写一个简单的View然后包在item的外面,然后监听手势操作,其它的也都不用更改,结果…..菜的抠脚没有实现,然后就只能重写RecyclerView,发现也没有我想象中的难。其核心就是重写onTouchEvent。通过对手指滑动的方向、距离、速度的判断,来决定是否要显示出删除按钮。
效果图:
这里写图片描述

这里面首先更改了item的布局文件如下。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
        <LinearLayout
            android:id="@+id/item_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:paddingTop="20dp">
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:id="@+id/im_item"
                    android:layout_gravity="center"
                    android:background="@mipmap/ic_launcher"/>
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:id="@+id/tv_item"
                    android:textColor="#030202"/>
            </LinearLayout>
            <TextView
                android:id="@+id/item_delete"
                android:layout_width="100dp"
                android:layout_height="match_parent"
                android:background="#88ff0000"
                android:gravity="center"
                android:text="删除"
                android:textColor="#ffffff"
                android:textSize="20sp" >
            </TextView>
        </LinearLayout>

</RelativeLayout>

就是在原本的LinearLayout外面嵌套了一个orientation=horizontal的LinearLayout,然后要把linnearLayout的width设成match_parent,再把总布局改成RelativeLayout这也相当重要的一部。然后这个TextView就是我们朝思暮想的删除按钮了。下面讲解一下重写的ONtouchEvent事件,本来我就是想点播一下,让同学们自己去尝试一下的,但总是怕出点状况..还是贴出所有代码吧。
下面贴重写的RecyclerView,(本来就不太会捕捉触摸事件。。写起来要了小命)

package com.sp.recycleview;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

/**
 * Created by my on 2016/10/25.
 */
public class MyRecyclerView extends RecyclerView{
    private Context mcontext;
    private int mLastX,mLastY;
    private int mPosition;
    private LinearLayout mItemLayout;
    private TextView mDelete;
    private int mMaxLength;
    private boolean isDragging;
    private boolean isItemMoving;
    private boolean isStartScroll;
    private int mDeleteBtnState;
    private VelocityTracker mVelocityTracker;
    private Scroller mScroller;
    private OnItemClickListener mListener;
    public MyRecyclerView(Context context){
        this(context,null);}
    public MyRecyclerView(Context context,@Nullable AttributeSet attributeSet){
        this(context,attributeSet,0);
    }
    public MyRecyclerView(Context context,@Nullable AttributeSet attributeSet,int defsytle){
        super(context, attributeSet, defsytle);
        mcontext=context;
        mScroller=new Scroller(context,new LinearInterpolator());
        mVelocityTracker=VelocityTracker.obtain();
    }
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        mVelocityTracker.addMovement(e);

        int x = (int) e.getX();
        int y = (int) e.getY();
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (mDeleteBtnState == 0) {
                    Log.e("0", "state:0");
                    View view = findChildViewUnder(x, y);
                    if (view == null) {
                        return false;
                    }

                    MyViewHolder viewHolder = (MyViewHolder) getChildViewHolder(view);//获得view

                    mItemLayout = viewHolder.layout;
                    mPosition = viewHolder.getPosition();

                    mDelete = (TextView) mItemLayout.findViewById(R.id.item_delete);
                    mMaxLength = mDelete.getWidth();
                    mDelete.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Log.e("0","mmm:");
                            mListener.onDeleteClick(mPosition);
                            mItemLayout.scrollTo(0, 0);
                            mDeleteBtnState = 0;
                        }
                    });
                } else if (mDeleteBtnState == 3){
                    Log.e("0","state:3");
                    mScroller.startScroll(mItemLayout.getScrollX(), 0, -mMaxLength, 0, 200);
                    invalidate();
                    mDeleteBtnState = 0;
                    return false;
                }else{
                    Log.e("0","state:???");
                    return false;
                }

                break;
            case MotionEvent.ACTION_MOVE:
                int dx = mLastX - x;
                int dy = mLastY - y;

                int scrollX = mItemLayout.getScrollX();
                if (Math.abs(dx) > Math.abs(dy)) {//左边界检测
                    isItemMoving = true;
                    if (scrollX + dx <= 0) {
                        mItemLayout.scrollTo(0, 0);
                        return true;
                    } else if (scrollX + dx >= mMaxLength) {//右边界检测
                        mItemLayout.scrollTo(mMaxLength, 0);
                        return true;
                    }
                    mItemLayout.scrollBy(dx, 0);//item跟随手指滑动
                }
                break;
            case MotionEvent.ACTION_UP:
                if (!isItemMoving && !isDragging && mListener != null) {
                    mListener.onClick(mPosition);
                }
                isItemMoving = false;

                mVelocityTracker.computeCurrentVelocity(1000);//计算手指滑动的速度
                float xVelocity = mVelocityTracker.getXVelocity();//水平方向速度(向左为负)
                float yVelocity = mVelocityTracker.getYVelocity();//垂直方向速度

                int deltaX = 0;
                int upScrollX = mItemLayout.getScrollX();

                if (Math.abs(xVelocity) > 100 && Math.abs(xVelocity) > Math.abs(yVelocity)) {
                    if (xVelocity <= -100) {//左滑速度大于100,则删除按钮显示
                        deltaX = mMaxLength - upScrollX;
                        mDeleteBtnState = 2;
                    } else if (xVelocity > 100) {//右滑速度大于100,则删除按钮隐藏
                        deltaX = -upScrollX;
                        mDeleteBtnState = 1;
                    }
                } else {
                    if (upScrollX >= mMaxLength / 2) {//item的左滑动距离大于删除按钮宽度的一半,则则显示删除按钮
                        deltaX = mMaxLength - upScrollX;
                        mDeleteBtnState = 2;
                    } else if (upScrollX < mMaxLength / 2) {//否则隐藏
                        deltaX = -upScrollX;
                        mDeleteBtnState = 1;
                    }
                }

                //item自动滑动到指定位置
                mScroller.startScroll(upScrollX, 0, deltaX, 0, 200);
                isStartScroll = true;
                invalidate();

                mVelocityTracker.clear();
                break;
        }

        mLastX = x;
        mLastY = y;
        return super.onTouchEvent(e);
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            mItemLayout.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        } else if (isStartScroll) {
            isStartScroll = false;
            if (mDeleteBtnState == 1) {
                mDeleteBtnState = 0;
            }

            if (mDeleteBtnState == 2) {
                mDeleteBtnState = 3;
            }
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        mVelocityTracker.recycle();
        super.onDetachedFromWindow();
    }



    public void setOnItemClickListener(OnItemClickListener listener) {
        mListener = listener;
    }
}

对触摸做了巨多的判断,可能就是因为这个我发现滑动的效率不是很高,以后想到了解决办法再来写个2.0
还有要注意既然我们的item新增加了一个TextView所以要在bolder里面加上

public TextView delete;
delete=(TextView)itemView.findViewById(R.id.item_delete);

还有就是这里既然有滑动所以肯定是一个LinearLayout整体滑动,所以也要给我们后加上的LinearLayout命名id然后在holder里面加上它。

public LinearLayout layout;
layout=(LinearLayout)view.findViewById(R.id.item_layout);

最后放一下最后的实现全部功能的MainActivyty吧。

package com.sp.recycleview;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private MyRecyclerView recyclerView;
    private List<String> mDatas;
    private MyRecyclerAdapter recycleAdapter;
    private SwipeRefreshLayout swipeRefreshLayout;

    @SuppressLint("NewApi") @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (MyRecyclerView) findViewById(R.id.recyclerview );


        swipeRefreshLayout=(SwipeRefreshLayout)findViewById(R.id.swipe_container);
        swipeRefreshLayout.setColorSchemeResources(R.color.colorAccent,R.color.colorPrimary,R.color.black,R.color.white);
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                Log.e("0", "正在刷新");
                new Handler().postDelayed(new Runnable(){
                    @Override
                    public void run() {
                        Log.e("0", "刷新完成");
                        recycleAdapter.addData(0);
                        swipeRefreshLayout.setRefreshing(false);
                    }
                }, 2000);
            }
        });

        initData();
        recycleAdapter= new MyRecyclerAdapter(this , mDatas );
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        GridLayoutManager gridLayoutManager=new GridLayoutManager(this,2);
        StaggeredGridLayoutManager staggeredGridLayoutManager= new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        //设置布局管理器
        recyclerView.setLayoutManager(layoutManager);
        //设置为垂直布局,这也是默认的
        layoutManager.setOrientation(OrientationHelper.VERTICAL);
        //设置Adapter
        recyclerView.setAdapter(recycleAdapter);
        //设置增加或删除条目的动画
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this, LinearLayoutManager.VERTICAL));
        recyclerView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onClick(int position) {
                Toast.makeText(MainActivity.this, "onClick事件       您点击了第:" + position + "个Item", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onDeleteClick(int position) {
                recycleAdapter.removeData(position);
            }
        });
    }

    private void initData() {
        mDatas = new ArrayList<String>();
        for ( int i=0; i<55; i++) {
            mDatas.add( "item"+i);
        }
    }
}

差点漏掉了…这个触摸删除时间还没有注册接口.要添加一句

void onDeleteClick(int position);

到此为止就实现了下拉刷新和左滑删除的全部功能了。楼主先去吃饭,晚上可能还有一篇学习心得。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值