笔记:Android二级联动---RecyclerView实现

做笔记免得以后有重写一边或者忘了,仅供自己学习(只实现功能,无动画实现,左边没做可见处理,有空再做吧):
1、左右两个RecyclerView,
2、左边RecyclerView点击某个item同时item改变背景颜色,右边RecyclerView置顶相对应的item
3、右边RecyclerView滑动,左边RecyclerView相对应的item被选中并且改变颜色
image.png

1、MainActivity.java中使用

package com.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

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

public class MainActivity extends AppCompatActivity {

    private isScroll=false;
    private RecyclerView rv_left_classify;
    private RecyclerView rv_right_classify;
    private List<String> dataList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        rv_left_classify= (RecyclerView) findViewById(R.id.rv_left_classify);//左边recyclerview
        rv_right_classify= (RecyclerView) findViewById(R.id.rv_right_classify);//右边recyclerview
        initViewAndData();
    }

    public void initViewAndData() {

        dataList=new ArrayList<>();
        for (int i=0;i<20;i++){
            dataList.add("数据第"+i+"条");
        }

        //右边recyclerview
        //这个是自定义后的LayoutManager
        final RecyclerView.LayoutManager layoutManagerRight=new AdvertiseLinearLayoutManager(this, LinearLayoutManager.VERTICAL,false);
        rv_right_classify.setLayoutManager(layoutManagerRight);
        ClassifyRVRightAdapter classifyAdapterRight=new ClassifyRVRightAdapter(this,dataList);
        rv_right_classify.setAdapter(classifyAdapterRight);

        //左边recyclerview
        RecyclerView.LayoutManager layoutManager=new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
        rv_left_classify.setLayoutManager(layoutManager);
        final ClassifyRVLeftAdapter classifyRVAdapterLeft=new ClassifyRVLeftAdapter(this,dataList);
        rv_left_classify.setAdapter(classifyRVAdapterLeft);

        //右边recyclerview
        //右边recyclerview在滚动的时候监听第一个可见或者最后可见的item,这里是利用LayoutManager才可以监听到的
        rv_right_classify.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                //判断是当前layoutManager是否为LinearLayoutManager
                // 只有LinearLayoutManager才有查找第一个和最后一个可见view位置的方法
                int lastItemPosition = 0;//最后可见 右边
                int firstItemPosition;//第一次可见 右边
                if (layoutManager instanceof LinearLayoutManager) {
                    LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
                    //获取最后一个可见view的位置    这两个随便选一个
                    lastItemPosition = linearManager.findLastVisibleItemPosition();
                    //获取第一个可见view的位置
                    firstItemPosition = linearManager.findFirstVisibleItemPosition();
                  
                   Log.e("可见item的位置--->>","最后一个可见=="+lastItemPosition+ "第一个可见==" + firstItemPosition);
                }
                //设置左边的RecyclerView的被点击
                classifyRVAdapterLeft.setSelectedPosition(lastItemPosition);
                //刷新左边的RecyclerView,否则选中无效(亲自踩坑)
                classifyRVAdapterLeft.notifyDataSetChanged();
            }
         }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                //如果是手动滑动右边RecyclerView,则isScroll为true,要刷新左边的RecyclerView,否则为false,不刷新
                //这里说明一下,newState的三种情况
              //RecyclerView停止滚动public static final int SCROLL_STATE_IDLE = 0;//RecyclerView正在被外部拖拽,一般为用户正在用手指滚动public static final int SCROLL_STATE_DRAGGING = 1;//自动滚动开始public static final int SCROLL_STATE_SETTLING = 2;
                if (newState==RecyclerView.SCROLL_STATE_DRAGGING){
                    isScroll=true;
                }else {
                    isScroll=false;
                }
        });

        //左边recyclerview
        //点击左边的RecyclerView的某个item,右边RecyclerView相对应指定item
        classifyRVAdapterLeft.setOnItemClickListener(new ClassifyRVLeftAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                //右边RecyclerView相对应置顶
                rv_right_classify.smoothScrollToPosition(position);
                //左边的RecyclerView被选中时改变背景颜色
                classifyRVAdapterLeft.setSelectedPosition(position);
                //刷新左边被选中的item,否则背景颜色不改变无效(亲自踩坑)
                classifyRVAdapterLeft.notifyDataSetChanged();
            }
        });
    }
}

2、自定义LinearLayoutManager--------->>AdvertiseLinearLayoutManager.java

当左边RecyclerView的某个item被选中,右边RecyclerView要置顶相对应的item,但是RecyclerView的本身的rv_right_classify.smoothScrollToPosition(position);的方法无法满足。所以我自定义了LinearSmoothScroller 与LinearLayoutManager(具体为啥就不深究了,只是做个笔记方便自己以后用到)

package com.myapplication;

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;

/**
 * Created by lenovo on 2017/12/8.
 */

  public class AdvertiseLinearLayoutManager extends LinearLayoutManager {

    public AdvertiseLinearLayoutManager(Context context) {
        super(context);
    }
    public AdvertiseLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public AdvertiseLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        AdvertiseLinearSmoothScroller linearSmoothScroller =
                new AdvertiseLinearSmoothScroller(recyclerView.getContext());
        linearSmoothScroller.setTargetPosition(position);
        startSmoothScroll(linearSmoothScroller);
    }
}

3、自定义LinearSmoothScroller

package com.myapplication;

import android.content.Context;
import android.support.v7.widget.LinearSmoothScroller;
import android.util.DisplayMetrics;

/**
 * Created by lenovo on 2017/12/8.
 */

class AdvertiseLinearSmoothScroller extends LinearSmoothScroller {

    public AdvertiseLinearSmoothScroller(Context context) {
        super(context);
    }

    /**
     *
     * @param viewStart RecyclerView的top位置
     * @param viewEnd RecyclerView的Bottom位置
     * @param boxStart item的top位置
     * @param boxEnd  item的bottom位置
     * @param snapPreference 滑动方向的识别
     * @return
     */
    @Override
    public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
        return boxStart-viewStart;//返回的就是我们item置顶需要的偏移量
    }

    /**
     * 此方法返回滚动每1px需要的时间,可以用来控制滚动速度
     * 即如果返回2ms,则每滚动1000px,需要2秒钟
     * @param displayMetrics
     * @return
     */
    @Override
    protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
        return super.calculateSpeedPerPixel(displayMetrics);
    }
}

4、左边RecyclerView的Adapter------>>>>ClassifyRVLeftAdapter.java

package com.myapplication;

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

/**
 * Created by lenovo on 2017/12/8.
 */

public class ClassifyRVLeftAdapter extends     RecyclerView.Adapter<ClassifyRVLeftAdapter.MyViewHolder>  implements View.OnClickListener {

    private List<String> mDatas;
    private Context mContext;
    private LayoutInflater inflater;

    private int selectedPosition = 0;

    private OnItemClickListener mOnItemClickListener = null;
    private View viewClassify;

    //define interface
    public static interface OnItemClickListener {
        void onItemClick(View view, int position);
    }


    public ClassifyRVLeftAdapter(Context context, List<String> datas){
        this. mContext=context;
        this. mDatas=datas;
        inflater= LayoutInflater. from(mContext);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view  = inflater.inflate(R.layout.item_classify_rv_adapter,parent, false);
        MyViewHolder holder= new MyViewHolder(view);
        view.setOnClickListener(this);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.tv.setText( mDatas.get(position));
        //选中和没选中时,设置不同的颜色
        if (position == selectedPosition) {
            holder.tv.setBackgroundColor(Color.GRAY);
        } else {
            holder.tv.setBackgroundColor(Color.WHITE);
        }
        holder.itemView.setTag(position);
    }


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

    @Override
    public void onClick(View view) {
        if (mOnItemClickListener != null) {
            //注意这里使用getTag方法获取position
            mOnItemClickListener.onItemClick(view,(int)view.getTag());
        }
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mOnItemClickListener = listener;
    }

    public void setSelectedPosition(int selectedPosition) {
        this.selectedPosition = selectedPosition;
    }

    public int getSelectedPosition() {
        return selectedPosition;
    }


    class MyViewHolder extends RecyclerView.ViewHolder
    {

        TextView tv;

        public MyViewHolder(View view)
        {
            super(view);
            tv = (TextView) view.findViewById(R.id.classsify_tv);
        }
    }

}

4.1、左边RecyclerView的item布局 item_classify_rv_adapter.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/classsify_tv"
    android:gravity="center"
    android:paddingTop="5dp"
    android:paddingBottom="5dp"
    android:layout_width="120dp"
    android:layout_height="wrap_content">
</TextView>

#5、右边RecyclerView的adapter------->>>>>>ClassifyRVRightAdapter.java

package com.myapplication;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.util.List;


/**
 * Created by lenovo on 2017/12/8.
 */

public class ClassifyRVRightAdapter extends RecyclerView.Adapter<ClassifyRVRightAdapter.MyViewHolder>{

    private List<String> mDatas;
    private Context mContext;
    private LayoutInflater inflater;

    public ClassifyRVRightAdapter(MainActivity context, List<String> datas) {
        this.mContext = context;
        this.mDatas = datas;
        inflater = LayoutInflater.from(mContext);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.item_classify_right, parent, false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.txt_two_tit.setText(mDatas.get(position));

    }


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

    class MyViewHolder extends RecyclerView.ViewHolder {

        TextView txt_two_tit;
        MyGridView my_gridview;

        public MyViewHolder(View view) {
            super(view);
            txt_two_tit = (TextView) view.findViewById(R.id.txt_two_tit);//标题
            my_gridview = (MyGridView) view.findViewById(R.id.my_gridview);
            my_gridview.setAdapter(new GridViewAdapter());
            my_gridview.setNumColumns(2);
            my_gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
                    Log.e("aaaa","被点击");
                }
            });
        }
    }
    class GridViewAdapter extends android.widget.BaseAdapter {


        @Override
        public int getCount() {
            return mDatas.size();
        }

        @Override
        public Object getItem(int position) {
            return position;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View view, ViewGroup viewGroup) {
            ViewHolder mHolder;
            if (view == null) {
                mHolder = new ViewHolder();
                view = LayoutInflater.from(viewGroup.getContext())
                        .inflate(R.layout.item_hot_sale, viewGroup, false);
                mHolder.image_commodity = (ImageView) view.findViewById(R.id.image_commodity);
                mHolder.txt_name = (TextView) view.findViewById(R.id.txt_name);
                view.setTag(mHolder);
            } else {
                mHolder = (ViewHolder) view.getTag();
            }
            if (mDatas != null) {
                Glide.with(mContext).load(R.mipmap.ic_launcher).into(mHolder.image_commodity);
                mHolder.txt_name.setText(mDatas.get(position));
            }
            return view;
        }

        private class ViewHolder {
            private ImageView image_commodity;
            private TextView txt_name;
        }
    }
}

5.1、右边adapter的item布局 item_classify_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:gravity="center"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#10000000"
        android:gravity="center"
        android:orientation="horizontal">

        <TextView
            android:layout_width="40dp"
            android:layout_height="1dp"
            android:layout_gravity="center_vertical"
            android:background="@color/colorAccent" />

        <TextView
            android:id="@+id/txt_two_tit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="12dp"
            android:text="222222" />

        <TextView
            android:layout_width="40dp"
            android:layout_height="1dp"
            android:layout_gravity="center_vertical"
            android:background="@color/colorAccent" />
    </LinearLayout>

    <com.myapplication.MyGridView
        android:id="@+id/my_gridview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

5.2、右边RecyclerView中的自定义GridView—>>>MyGridView.java

package com.myapplication;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.GridView;

/**
 * Created by Administrator on 2017/2/13 0013.
 */

public class MyGridView extends GridView {

    public MyGridView(Context context) {
        super(context);
    }

    public MyGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}

5.3、右边RecyclerView中的MyGridView的item布局 item_hot_sale.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:id="@+id/item_hot_sale"
    android:orientation="vertical">

          <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="10dp"
            android:paddingTop="10dp"
            android:orientation="vertical" >

        <ImageView
            android:id="@+id/image_commodity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:src="@mipmap/ic_launcher"
            android:scaleType="fitXY"
            />

        <TextView
            android:id="@+id/txt_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="女装"
            android:layout_marginTop="3dp"
            android:layout_gravity="center_horizontal"
            android:textColor="@android:color/black" />
        </LinearLayout>
</LinearLayout>

加强版:右边悬浮+decoration修饰分割线

效果还是挺流畅的,只是gif有点卡,凑合着看吧

在这里插入图片描述

仅供学习之用

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
联动 RecyclerView:即使不用饿了么订餐,也请务必收藏好该库!由来Linkage-RecyclerView 是一款基于 MVP 架构开发的二级联动列表控件。它是因 “RxJava 魔法师” 这个项目的需求而存在。在最初寻遍了 GitHub 也没有找到合适的开源库(高度解耦、可远程依赖)之后,我决心研究参考现有开源项目关于二级联动的逻辑,并自己动手编写一个 高度解耦、轻松配置、可通过 maven 仓库远程依赖 的真正的第三方库。Linkage-RecyclerView 的个性化配置十分简单,依托于 MVP 的 “配置解耦” 特性,使用者无需知道内部的实现细节,仅通过实现 Config 类即可完成功能的定制和扩展。此外,在不设置自定义配置的情况下,LinkageRecyclerView 最少只需 一行代码即可运行起来。RxMagicEleme LinearEleme Grid目标Linkage-RecyclerView 的目标是:一行代码即可接入二级联动列表。除了一键接入而省去 99% 不必要的、复杂的、重复的工作外,你还可以从这个开源项目获得的内容包括:整洁的代码风格和标准的资源命名规范。MVP 架构在第三库中的最佳实践:使用者无需了解内部逻辑,通过实现接口即可轻松完成个性化配置。优秀的代码分层和封装思想,在不做任何个性化配置的情况下,一行代码即可接入。主体工程基于前沿的、遵循关注点分离的 JetPack MVVM 架构。AndroidX 和 Material Design 2 的全面使用。ConstraintLayout 约束布局的最佳实践。绝不使用 Dagger,绝不使用奇技淫巧、编写艰深晦涩的代码。如果你正在思考 如何为项目挑选合适的架构 的话,这个项目值得你参考!简单使用:1.在 build.gradle 中添加对该库的依赖。implementation 'com.kunminx.linkage:linkage-recyclerview:1.2.0'2.依据默认的联动实体类(DefaultLinkageItem)的结构准备一串 JSON。// DefaultLinkageItem.ItemInfo 包含三个字段: String title //二级选项的标题(必填) String group //二级选项所在分组的名称,要和对应的一级选项的标题相同(必填) String content //二级选项的内容(选填)[   {     "header": "优惠",     "isHeader": true   },   {     "isHeader": false,     "t": {       "content": "好吃的食物,增肥神器,有求必应",       "group": "优惠",       "title": "全家桶"     }   },   {     "header": "热卖",     "isHeader": true   } ]3.在布局中引入 LinkageRecyclerView 。<?xml version="1.0" encoding="utf-8"?>      4.在代码中解析 JSON,最少只需一行代码即可完成初始化。List items = gson.fromJson(...); //一行代码完成初始化 linkage.init(items);个性化配置:该库为一级和二级 Adapter 分别准备了 Config 接口(ILevelPrimaryAdapterConfig 和 ILevelSecondaryAdapterConfig),自定义配置时,即是去实现这两个接口,来取代默认的配置。之所以设置成接口的形式,而非 Builder 的形式,是因为二级联动列表内部的联动
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值