RecyclerView双列表联动

双列表联动效果如下:

以上,是博主根据鸿洋大神的玩Android开放的API做的一个客户端,其中导航界面使用了双列表联动来展示数据。

一、前期基础知识储备

1.使用强大的开源项目BRVAH装载两个列表的数据,简单易用,强烈推荐使用;

2.RecyclerView的滚动事件OnScrollListener研究 - 监听列表滚动状态的接口为 RecyclerView.OnScrollListener

注册接口的方法有两个:

1).setOnScrollListener(OnScrollListener listener) ,可能会有空指针问题,已经被废弃。

2).addOnScrollListener(OnScrollListener listener)

3.OnScrollListener类是个抽象类,有两个方法:

void onScrollStateChanged(RecyclerView recyclerView, int newState): 滚动状态变化时回调

recyclerView: 当前在滚动的RecyclerView

newState: 当前滚动状态 void onScrolled(RecyclerView recyclerView, int dx, int dy): 滚动时回调

recyclerView : 当前滚动的view

dx : 水平滚动距离

dy : 垂直滚动距离

dx > 0 时为手指向左滚动,列表滚动显示右面的内容

dx < 0 时为手指向右滚动,列表滚动显示左面的内容

dy > 0 时为手指向上滚动,列表滚动显示下面的内容

dy < 0 时为手指向下滚动,列表滚动显示上面的内容

4.RecycleView4种定位滚动方式演示

1)recyclerView.scrollBy(x, y),这个方法是自己去控制移动的距离,单位是像素;

2)recyclerView.scrollToPosition(position),这个方法的作用是定位到指定项,就是把你想显示的项显示出来,但是在屏幕的什么位置是不管的,只要那一项现在看得到了,那它就罢工了;

3)recyclerView.smoothScrollToPosition(position),smoothScrollToPosition(position)scrollToPosition(position)效果基本相似,也是把你想显示的项显示出来,只要那一项现在看得到了,那它就罢工了,不同的是smoothScrollToPosition是平滑到你想显示的项,而scrollToPosition是直接定位显示;

4)((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(position,0);主角总是最后才登场,这种方式是定位到指定项如果该项可以置顶就将其置顶显示。比如:微信联系人的字母索引定位就是采用这种方式实现。

二、上代码,具体实现

1.在布局中放入两个RecyclerView,左右各一个;




    

    

2.使用BRVAH开源项目,做好两个列表的适配器;

①右边的列表适配器:

public class RightAdapter extends BaseQuickAdapter {
    public RightAdapter(int layoutResId) {
        super(layoutResId);
    }

    @Override
    protected void convert(BaseViewHolder holder, GuideBean.DataBean item) {
        holder.getView(R.id.tv_item_tixi).setVisibility(View.GONE); // 右侧列表不为item设立标题
        TagFlowLayout tfl = holder.getView(R.id.tfl);
        ArrayList mVals = new ArrayList<>();
        for (int i = 0; i < item.getArticles().size(); i++) {
            mVals.add(item.getArticles().get(i).getTitle());
        }
        tfl.setAdapter(new TagAdapter(mVals) {
            @Override
            public View getView(FlowLayout parent, int position, String s) {
                Random random = new Random();
                int r = random.nextInt(150);
                int g = random.nextInt(150);
                int b = random.nextInt(150);
                TextView tv = (TextView) LayoutInflater.from(mContext).inflate(R.layout.tfl, tfl, false);
                tv.setTextColor(Color.rgb(r, g, b));
                tv.setText(s);
                return tv;
            }
        });

        tfl.setOnTagClickListener((view, position, parent) -> {
            Intent intent = new Intent(mContext, WebViewActivity.class);
            intent.putExtra("link", item.getArticles().get(position).getLink());
            mContext.startActivity(intent);
            Log.d(TAG, "getView: " + item.getArticles().get(position).getLink() + "," + position);
            return false;
        });
    }
}

②左边的列表适配器:

public class LeftAdapter extends BaseQuickAdapter {
    private ArrayList selected = new ArrayList<>();
    private int position;

    public ArrayList getSelected() {
        return selected;
    }

    public LeftAdapter(int layoutResId) {
        super(layoutResId);
    }

    @Override
    protected void convert(BaseViewHolder holder, GuideBean.DataBean item) {
        holder.setText(R.id.tv_title, item.getName());
        holder.setBackgroundColor(R.id.view, holder.getLayoutPosition() == position ? Color.parseColor("#ffffff") : Color.parseColor("#363636"));
    }

    public void setSelect(ArrayList booleans) {
        this.selected = booleans;
        notifyDataSetChanged();
    }

    public void setSelection(int pos) {
        Log.d(TAG, "setSelection: " + pos);
        this.position = pos;
        notifyDataSetChanged();
    }
}

3.使用OKGO请求网络数据,同时填充两个适配器:

private void getData() {
        OKGO.get(Constants.NAVIURL, "navifragment", new StringCallback() {
            @Override
            public void onSuccess(Response response) {
                GuideBean resultBean = JSONObject.parseObject(response.body(), GuideBean.class);
                int errorCode = resultBean.getErrorCode();
                if (errorCode == 0) {
                    articlesBeanList = new ArrayList<>();
                    dataBeanList = resultBean.getData();

                    for (int i = 0; i < dataBeanList.size(); i++) {
                        articlesBeanList.addAll(dataBeanList.get(i).getArticles());
                    }

                    leftAdapter = new LeftAdapter(R.layout.item_text);
                    rv1.setAdapter(leftAdapter);
                    leftAdapter.setNewData(dataBeanList);

                    rightAdapter = new RightAdapter(R.layout.item_tixi);
                    rv2.setAdapter(rightAdapter);
                    if (dataBeanList != null) {
                        rightAdapter.setNewData(dataBeanList);
                    }

            ... ...

            @Override
            public void onError(Response response) {
                super.onError(response);
            }

            @Override
            public void onFinish() {
                super.onFinish();

            }
        });
    }

4.写入双列表联动的控制;

点击左边列表,右边列表进行滑动

                    leftAdapter.setOnItemClickListener((adapter, view, position) -> {
                        leftAdapter.setSelection(position);
                        LinearLayoutManager layoutManager = (LinearLayoutManager) rv2.getLayoutManager();
                        ... ...
                        //根据左侧,定位右侧的展示数据
                        layoutManager.scrollToPositionWithOffset(position, 0); // 定位到某个item,并将其置顶显示


                    });

滑动右侧列表,左侧列表进行联动

                    rv2.addOnScrollListener(new RecyclerView.OnScrollListener() {
                        @Override
                        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                            super.onScrolled(recyclerView, dx, dy);
                            //获取滚动时的第一条展示的position
                            LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                            int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
                            int position = 0;
                            for (int i = 0; i < firstVisibleItemPosition; i++) {
                                position += dataBeanList.get(i).getArticles().size();
                            }

                            //获取右侧数据的关联id
                            GuideBean.DataBean.ArticlesBean articlesBean = articlesBeanList.get(position);
                            int outId = articlesBean.getChapterId();
                            //记录外部id, 更新左侧状态栏状态
                            int pos = 0;
                            for (int i = 0; i < dataBeanList.size(); i++) {
                                int id = dataBeanList.get(i).getCid();
                                if ((outId == id)) {
                                    pos = i;
                                }
                            }
                            leftAdapter.setSelection(pos);
                            rv1.smoothScrollToPosition(pos);
                        }
                    });
                } 

这里比较关键,首先我们需要获取右侧列表第一个Item项的位置,然后获取它的一个索引值,与左侧列表的索引值进行比较,看看某个属性会相等,相等则说明,右侧列表项归属于某个左侧列表项。这个属性由鸿洋大神提供的API返回的JSON数据可知为:

左侧列表属性:cid,一个int类型的值;

右侧列表属性:chapterId,一个int类型的值。

只要两个值相等,则判定左侧的列表需要进行滑动。

另外推荐一个已开源的双列表联动的项目:

Linkage-RecyclerView

 

你可能感兴趣的:(高级要求)