淘宝京东的相对简单很多,两个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