Android 仿京东淘宝拼多多的商品分类,双列表联动,RecyclerView嵌套

淘宝京东的相对简单很多,两个RecyclerView就可实现了。

现在要做的是右边滑动的时候左边跟着联动,如下图:

思路:左右肯定都是RecyclerView了,至于中间的图片嘛当然也是RecyclerView了,嵌套冲突的时代已经过去了。(如果你想用多条目,每张图片也要复用我也不反对,但你会掉头发...)

注意:嵌套的内层RecyclerView会失去复用,不适合单个分类上百张图片(是单个分类,不是总数)或一张图片需要占半屏的那种(真有有这么奇葩的分类我也无力吐槽)

 

其实代码不算太复杂,就是逻辑有点绕,精简炼化后的代码如下:

public class RvLianDongActivity extends BaseActivity {

    @BindView(R.id.rv_rvliandong_Left)
    RecyclerView mRvLeft;
    @BindView(R.id.rv_rvliandong_Right)
    RecyclerView mRvRight;

    private RvLeftAdapter mAdapterLeft;
    private RvRightAdapter mAdapterRight;

    private LinearLayoutManager mManagerLeft;
    private LinearLayoutManager mManagerRight;

    /**
     * 是否来自点击
     */
    private boolean mIsFromClick = false;

    /**
     * 相当于setContentView
     */
    @Override
    protected int getLayouRes() {
        return R.layout.activity_rv_lian_dong;
    }

    /**
     * 相当于onCreate的初始逻辑
     */
    @Override
    protected void initData() {
        mRvLeft.setLayoutManager(new LinearLayoutManager(this));
        mAdapterLeft = new RvLeftAdapter(this);
        mRvLeft.setAdapter(mAdapterLeft);

        mManagerRight = new LinearLayoutManager(this);
        mRvRight.setLayoutManager(mManagerRight);
        mAdapterRight = new RvRightAdapter(this);
        mRvRight.setAdapter(mAdapterRight);

        //造数据
        ArrayList<String> listLeft = new ArrayList<>();
        ArrayList<String> listRight = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            listLeft.add("左边第" + i);
            listRight.add("右边第" + i);
        }
        mAdapterLeft.setListAndNotifyDataSetChanged(listLeft);//就是设置list然后刷新
        mAdapterRight.setListAndNotifyDataSetChanged(listRight);

        //监听
        mRvRight.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int i, int i1) {
                super.onScrolled(recyclerView, i, i1);
                if (mIsFromClick) {//防止来回调
                    return;
                }
                changePosition();
            }

            private void changePosition() {
                int firstPosition = mManagerRight.findFirstVisibleItemPosition();
                if (mAdapterLeft.mCheckedPosition != firstPosition) {
                    mAdapterLeft.mCheckedPosition = firstPosition;
                    mAdapterLeft.notifyDataSetChanged();

                    //此方法无置顶效果
                    mRvLeft.scrollToPosition(mAdapterLeft.mCheckedPosition);
                }
            }
        });

        mAdapterLeft.setOnItemClickListener(new OnItemClickListener() {
            @Override
            protected void onItemClick(View view, int listPosition) {
                mAdapterLeft.mCheckedPosition = listPosition;
                mAdapterLeft.notifyDataSetChanged();
                mIsFromClick = true;//不走onScrolled,防止来回调
                //此方法可以置顶
                mManagerRight.scrollToPositionWithOffset(listPosition, 0);
                mIsFromClick = false;//放开
            }
        });
    }

    /**
     * 左边,就一个tv
     */
    public static class RvLeftAdapter extends BaseAdapterRvList<BaseViewHolder, String> {
        public int mCheckedPosition = 0;

        public RvLeftAdapter(Activity activity) {
            super(activity);
        }

        @Override
        protected void onBindVH(BaseViewHolder holder, int listPosition, String s) {
            TextView tv = (TextView) holder.itemView;
            tv.setText(s);
            tv.setBackgroundColor(mCheckedPosition == listPosition ? 0xffeeeeee : 0xffffffff);//选中灰色,不选择白色
        }

        @NonNull
        @Override
        protected BaseViewHolder onCreateVH(ViewGroup parent, LayoutInflater inflater) {
            TextView tv = new AppCompatTextView(mActivity);
            tv.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            tv.setPadding(0, 40, 0, 40);
            tv.setGravity(Gravity.CENTER);
            tv.setTextSize(15);
            return new BaseViewHolder(tv);
        }
    }

    /**
     * 右边tv+rv
     */
    public static class RvRightAdapter extends BaseAdapterRvList<RvRightAdapter.ViewHolder, String> {

        public RvRightAdapter(Activity activity) {
            super(activity);
        }

        @Override
        protected void onBindVH(ViewHolder holder, int listPosition, String s) {
            holder.mTvBiaoTi.setText(s);

            BaseAdapterRvList adapter = (BaseAdapterRvList) holder.mRv.getAdapter();

            ArrayList<Integer> list = new ArrayList<>();
            for (int i = 0; i < listPosition + 1; i++) {
                list.add(R.mipmap.ic_launcher);
            }
            adapter.setListAndNotifyDataSetChanged(list);//一堆机器人的图片
        }

        @NonNull
        @Override
        protected ViewHolder onCreateVH(ViewGroup parent, LayoutInflater inflater) {
            ViewHolder holder = new ViewHolder(inflater.inflate(R.layout.adapter_liandong_right, parent, false));
            holder.mRv.setLayoutManager(new GridLayoutManager(mActivity, 4));
            //此处为了简单,直接就是图片
            holder.mRv.setAdapter(new BaseAdapterRvList<BaseViewHolder, Integer>(mActivity) {

                @Override
                protected void onBindVH(BaseViewHolder holder, int listPosition, Integer integer) {
                    ImageView iv = (ImageView) holder.itemView;
                    iv.setImageResource(integer);
                }

                @NonNull
                @Override
                protected BaseViewHolder onCreateVH(ViewGroup parent, LayoutInflater inflater) {
                    ImageView iv = new AppCompatImageView(mActivity);
                    return new BaseViewHolder(iv);
                }
            });
            holder.mRv.setNestedScrollingEnabled(false);//设置内层rv不可滑动
            return holder;
        }

        static class ViewHolder extends BaseViewHolder {
            @BindView(R.id.tv_liandongrightada_BiaoTi)
            TextView mTvBiaoTi;
            @BindView(R.id.rv_liandongrightada)
            RecyclerView mRv;

            ViewHolder(View view) {
                super(view);
                ButterKnife.bind(this, view);
            }
        }
    }
}

activity_rv_lian_dong.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/c_fff"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <!--标题样式可以忽略-->
    <com.wang.mylibrary.view.ActivityHeaderView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:w_title="RV联动" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_rvliandong_Left"
            android:layout_width="0px"
            android:layout_height="match_parent"
            android:layout_weight="1" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_rvliandong_Right"
            android:layout_width="0px"
            android:layout_height="match_parent"
            android:layout_weight="3" />
    </LinearLayout>
</LinearLayout>

adapter_liandong_right.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/c_fff"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_liandongrightada_BiaoTi"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/w_c_eee"
        android:padding="5dp"
        android:text="标题" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_liandongrightada"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

想要点击左边加上惯性滑动效果?

把滑动监听和click事件改一下就行了,稍微复杂一点点:

        //监听
        mRvRight.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int i, int i1) {
                super.onScrolled(recyclerView, i, i1);
                if (mIsFromClick) {//防止来回调
                    return;
                }
                changePosition();
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    //和下面的handler配合,这样才能无bug
                    if (mIsFromClick) {
                        changePosition();//防止突然停了,定错位置
                    }
                    mIsFromClick = false;//滑动结束放开
                }
            }

            private void changePosition() {
                int firstPosition = mManagerRight.findFirstVisibleItemPosition();
                if (mAdapterLeft.mCheckedPosition != firstPosition) {
                    mAdapterLeft.mCheckedPosition = firstPosition;
                    mAdapterLeft.notifyDataSetChanged();

                    //此方法无置顶效果
                    mRvLeft.scrollToPosition(mAdapterLeft.mCheckedPosition);
                }
            }
        });

        mAdapterLeft.setOnItemClickListener(new OnItemClickListener() {
            @Override
            protected void onItemClick(View view, int listPosition) {
                mAdapterLeft.mCheckedPosition = listPosition;
                mAdapterLeft.notifyDataSetChanged();
                mIsFromClick = true;//不走onScrolled,防止来回调
                LinearSmoothScroller topScroller = new LinearSmoothScroller(getActivity()) {

                    @Override
                    protected int getHorizontalSnapPreference() {
                        return SNAP_TO_START;//具体见源码注释
                    }

                    @Override
                    protected int getVerticalSnapPreference() {
                        return SNAP_TO_START;//具体见源码注释
                    }

                    @Override
                    protected void onStop() {
                        super.onStop();
                        //发送一个延时handler
                        //因为onStop时还有惯性动画
                        TimeUtil.mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                mIsFromClick = false;
                            }
                        }, 500);
                    }
                };
                topScroller.setTargetPosition(listPosition);
                mManagerRight.startSmoothScroll(topScroller);
            }
        });

关于数据格式:

我的代码是单纯为了展示效果没有格式,真正的格式应该像这样:(tb、jd不是这样的,见下面原因)

[{
	"title": "左标题",
	"title2": "右标题",
	"ohter": "其他内容",
	"item": [{
		"img": "http:1",
		"ohter2": "其他内容"
	}...]
}..]

这种效果又流畅又时尚为什么tb、jd都不使用?

1.tb、jd分类比较多,一次性加载全部会比较慢,影响体验,服务器压力也会变大。

2.用户基本只会点其中几个分类,其他分类即使加载了也是浪费。

3.他们的分类下还有小分类,一直滑动会容易混淆。

所以他们采用了每次点击根据左边的标题来再请求网络获得右边的数据。

置顶效果:

置顶很简单,但好多人不知道,里面也有置顶失败的例子,详细见:https://blog.csdn.net/weimingjue/article/details/82805361

BaseAdapterRvList和BaseViewHolder:

就是Adapter对list的封装简化,详细代码:https://blog.csdn.net/weimingjue/article/details/8819075

 

转载请注明出处:王能的博客:https://blog.csdn.net/weimingjue/article/details/102698344

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值