Android控件开发——RecycleView的使用总结(中)

文/程序员男神

前言

今天这个天气就像星期一上班的情绪一样,阴沉沉的。最讨厌下雨天,也许,文艺男屌丝都喜欢有阳光的日子吧!一整天都在搞这个需求,一天除了调试接口,就是在弄它。赶紧记录一下,让寒冷的心情有点温暖。


Android控件开发——RecycleView的使用总结(中)_第1张图片
aj

概述

先上需求图:Recycleview左滑删除的需求。


Android控件开发——RecycleView的使用总结(中)_第2张图片
需求图

实现的功能细节:

  • 滑动时删除按钮显示在item底下,非后方平移出现
  • 内容项和删除按钮都可以点击
  • 当有滑动菜单显示时,点击任意项关闭滑动菜单
  • 当有滑动菜单显示时,滑动别的项关闭之前的滑动菜单
  • 删除的视觉动画效果(偷懒直接用了默认的)

实现步骤

首先是引用:

 compile 'com.android.support:appcompat-v7:25.0.1'
 compile 'com.android.support:recyclerview-v7:25.0.1'

自定义删除按钮的实现,自定义View继承水平滚动条,参考别人的代码,学以致用。
代码如下:

/**
 * desc: 侧滑按钮自定义
 * author: dj
 * date: 2017/3/10 10:01
 */

public class SlidingButtonView extends HorizontalScrollView {

    private TextView mTextView_Delete;
    private int mScrollWidth;
    private Boolean isOpen = false;
    private Boolean once = false;

    public SlidingButtonView(Context context) {
        this(context, null);
    }

    public SlidingButtonView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlidingButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.setOverScrollMode(OVER_SCROLL_NEVER);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!once) {
            mTextView_Delete = (TextView) findViewById(R.id.tv_delete);
            once = true;
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed) {
            this.scrollTo(0, 0);
            //获取水平滚动条可以滑动的范围,即右侧按钮的宽度
            mScrollWidth = mTextView_Delete.getWidth();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                mIonSlidingButtonListener.onDownOrMove(this);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                changeScrollx();
                return true;
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 按滚动条被拖动距离判断关闭或打开菜单
     */
    public void changeScrollx() {
        if (getScrollX() >= (mScrollWidth / 2)) {
            this.smoothScrollTo(mScrollWidth, 0);
            isOpen = true;
            mIonSlidingButtonListener.onMenuIsOpen(this);
        } else {
            this.smoothScrollTo(0, 0);
            isOpen = false;
        }
    }

    /**
     * 打开菜单
     */
    public void openMenu() {
        if (isOpen) {
            return;
        }
        this.smoothScrollTo(mScrollWidth, 0);
        isOpen = true;
        mIonSlidingButtonListener.onMenuIsOpen(this);
    }

    /**
     * 关闭菜单
     */
    public void closeMenu() {
        if (!isOpen) {
            return;
        }
        this.smoothScrollTo(0, 0);
        isOpen = false;
    }

    private IonSlidingButtonListener mIonSlidingButtonListener;

    public void setSlidingButtonListener(IonSlidingButtonListener listener) {
        this.mIonSlidingButtonListener = listener;
    }

    public interface IonSlidingButtonListener {
        void onMenuIsOpen(View view);

        void onDownOrMove(SlidingButtonView slidingButtonView);
    }
}

接下来我们看看activity的代码:

/**
 * desc: Recycle的简单使用
 * author: dj
 * date: 2017/3/2 9:57
 */

public class RecycleActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {

    private RecyclerView mRecyclerView;
    private RecycleAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private List list;
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private static final int REFRESH_STATUS = 0;
    private int j = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycle);

        initDate();
        initView();

    }

    private void initDate() {
        list = new ArrayList();
        for (int i = 0; i < 20; i++) {
            list.add("西红柿炒鸡蛋");
        }
    }

    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.recycle_view);
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);

        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mAdapter = new RecycleAdapter(RecycleActivity.this, list);
        mRecyclerView.setAdapter(mAdapter);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, android.R.color.holo_orange_light, android.R.color.holo_red_light);

        mSwipeRefreshLayout.post(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(true);
            }
        });
        onRefresh();
        mAdapter.setOnSlidingViewClickListener(new SwipeAdapter.IonSlidingViewClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(RecycleActivity.this, "单击" + position, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onDeleteBtnClick(View view, int position) {
                Toast.makeText(RecycleActivity.this, "删除" + position, Toast.LENGTH_SHORT).show();
                mAdapter.removeItem(position);
            }
        });
    }

    @Override
    public void onRefresh() {
        refreshHandler.sendEmptyMessageDelayed(REFRESH_STATUS, 2000);
    }

    private Handler refreshHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case REFRESH_STATUS:
                    //下拉刷新执行的操作,刷新数据
                    mSwipeRefreshLayout.setRefreshing(false);
                    j++;
                    list.add("测试" + j);
                    mAdapter.updateData(list);
                    break;
            }
        }
    };
}

其对应的activity_recycle.xml文件:




    

        
    

接下来就是最重要的adapter的写法了,代码如下:

/**
 * desc: RecycleView的Adapter
 * author: dj
 * data: 2017/2/28 15:20
 */

public class RecycleAdapter extends RecyclerView.Adapter implements SlidingButtonView.IonSlidingButtonListener {

    private Context mContext;
    private List data;
    private SlidingButtonView mMenu = null;

    //构造器,接受数据集
    public RecycleAdapter(Context context, List data) {
        mContext = context;
        this.data = data;
        //mIDeleteBtnClickListener = (IonSlidingViewClickListener) context;
    }

    public void updateData(List data) {
        this.data = data;
        notifyDataSetChanged();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        //将数据填充到具体的view中
        holder.icon.setImageResource(R.drawable.jian);
        holder.title.setText(data.get(position));
        holder.desc.setText(data.get(position));

        //设置内容布局的宽为屏幕宽度
        DisplayMetrics metrics = new DisplayMetrics();
        ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int width = metrics.widthPixels;
        holder.layout_content.getLayoutParams().width = width;
        if (mIDeleteBtnClickListener != null){
            holder.layout_content.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //判断是否有删除菜单打开
                    if (menuIsOpen()) {
                        closeMenu();//关闭菜单
                    } else {
                        int n = holder.getLayoutPosition();
                        mIDeleteBtnClickListener.onItemClick(v, n);
                    }
                }
            });
            holder.btn_Delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int n = holder.getLayoutPosition();
                    mIDeleteBtnClickListener.onDeleteBtnClick(v, n);
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        public ImageView icon;
        public TextView title;
        public TextView desc;
        public TextView btn_Delete;
        public ViewGroup layout_content;

        public ViewHolder(View itemView) {
            super(itemView);
            //由于itemView是item的布局文件,我们需要的是里面的textView,因此利用itemView.findViewById获
            //取里面的textView实例,后面通过onBindViewHolder方法能直接填充数据到每一个textView了
            icon = (ImageView) itemView.findViewById(R.id.item_image);
            title = (TextView) itemView.findViewById(R.id.item_title);
            desc = (TextView) itemView.findViewById(R.id.item_desc);
            btn_Delete = (TextView) itemView.findViewById(R.id.tv_delete);
            layout_content = (ViewGroup) itemView.findViewById(R.id.layout_content);
            ((SlidingButtonView) itemView).setSlidingButtonListener(RecycleAdapter.this);

        }
    }

    /**
     * 删除菜单打开信息接收
     */
    @Override
    public void onMenuIsOpen(View view) {
        mMenu = (SlidingButtonView) view;
    }

    /**
     * 滑动或者点击了Item监听
     *
     * @param slidingButtonView
     */
    @Override
    public void onDownOrMove(SlidingButtonView slidingButtonView) {
        if (menuIsOpen()) {
            if (mMenu != slidingButtonView) {
                closeMenu();
            }
        }
    }

    /**
     * 关闭菜单
     */
    public void closeMenu() {
        mMenu.closeMenu();
        mMenu = null;
    }

    /**
     * 判断是否有菜单打开
     */
    public Boolean menuIsOpen() {
        if (mMenu != null) {
            return true;
        }
        return false;
    }

    private SwipeAdapter.IonSlidingViewClickListener mIDeleteBtnClickListener;

    public void setOnSlidingViewClickListener(SwipeAdapter.IonSlidingViewClickListener listener) {
        this.mIDeleteBtnClickListener = listener;
    }

    public interface IonSlidingViewClickListener {
        void onItemClick(View view, int position);

        void onDeleteBtnClick(View view, int position);
    }

    /**
     * 向指定位置添加元素
     */
    public void addItem(int position, String value) {
        if (position > data.size()) {
            position = data.size();
        }
        if (position < 0) {
            position = 0;
        }
        /**
         * 使用notifyItemInserted/notifyItemRemoved会有动画效果
         * 而使用notifyDataSetChanged()则没有
         */
        data.add(position, value);//在集合中添加这条数据
        notifyItemInserted(position);//通知插入了数据
    }

    /**
     * 移除指定位置元素
     */
    public String removeItem(int position) {
        if (position > data.size() - 1) {
            return null;
        }
        String value = data.remove(position);//所以还需要手动在集合中删除一次
        notifyItemRemoved(position);//通知删除了数据,但是没有删除list集合中的数据
        return value;
    }
}

其那个的item_list.xml文件:





    

        

            

                

                

                    

                    
                
            
        

        
    


虽然只是一些代码的堆叠,但是它带给我的思想是很好的,希望大家看博客的时候不只是看到他的功能适不适合你,其实学习的更多是它们的思想。

码代码不易,转载须注明出处,违者必究!

注意事项:对item监听的回调要注意,是对谁监听?否则监听无效,现在bug已改。
参考文档:http://blog.csdn.net/tyzlmjj/article/details/47060817

你可能感兴趣的:(Android控件开发——RecycleView的使用总结(中))