美文网首页UIAndroid 三方集成Android
Android 仿京东分类功能实现

Android 仿京东分类功能实现

作者: 没有了遇见 | 来源:发表于2021-11-19 15:34 被阅读0次

业务需要实现类似京东分类页面的页面效果,原先没有写过类似的这种效果,特此搞个Demo 梳理一下整体的实现流程以及记录下逻辑实现的效果

一,效果

效果.gif

二,实现思路 RecycleView+Fragment(RecycleView)+观察

  .

  1:左侧是RecycleView 为了实现局部刷新 使用了DiffUtil   处理局部刷新问题

  2:右侧是一个Fragment 用了 SmartRefreshLayout,RecycleView处理刷新效果

  3.数据通讯使用了 ClassificationObservable,ClassificationFinshObservable两个观察者处理开始刷新以及刷新结束的状态

  .

三,代码实现

1.首页代码

package com.wu.third.classification

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.wu.base.adapter.KtAdapter
import com.wu.third.R
import com.wu.third.databinding.ActivityClassificationBinding
import java.util.*
import kotlin.collections.ArrayList


class ClassificationActivity : AppCompatActivity(), Observer {

 var binding: ActivityClassificationBinding? = null
 //右侧内容
 var currentFragment: ClassificationContentFragment? = null
 //左侧内容适配器
 var tagAdapter: ClassificationTagAdapter? = null
 //静态图片
 var imgs = arrayListOf<String>(
     "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F16%2F10%2F29%2F2ac8e99273bc079e40a8dc079ca11b1f.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=0b42192b10b6d521d58cd0650a0148e6",
     "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F17%2F09%2F15%2F67351408baad11ce25c9b14166a049a6.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=a6c67c2f08b86a82348b2c87e75ffd9c",
     "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Ftupian.qqjay.com%2Fu%2F2018%2F0222%2F2_163119_13.jpg&refer=http%3A%2F%2Ftupian.qqjay.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=995f87498f2d19ab6c885e09904d1ef3",
     "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fdpic.tiankong.com%2Ftc%2Feb%2FQJ9124407543.jpg&refer=http%3A%2F%2Fdpic.tiankong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=c76415814c9c52ae20480a89199a128c",
     "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fdpic.tiankong.com%2Ftc%2Feb%2FQJ9124407543.jpg&refer=http%3A%2F%2Fdpic.tiankong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=c76415814c9c52ae20480a89199a128c",
     "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fitbbs%2F1705%2F10%2Fc35%2F46579542_1494425402317_mthumb.jpg&refer=http%3A%2F%2Fimg.pconline.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=3ddc7531c2a48fd48712346466ebd228",
     "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp01%2F1ZZQ20QJS6-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=5f6463e28700d48143f6be2c554f8a28"
 )
 //左侧商品分类
 var tags = arrayListOf<ClassificationTagInfo>(
     ClassificationTagInfo("家电", true),
     ClassificationTagInfo("食品", false),
     ClassificationTagInfo("服装", false),
     ClassificationTagInfo("电子", false),
     ClassificationTagInfo("农产品", false),
     ClassificationTagInfo("饮料", false),
 )

 override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState)
     binding = DataBindingUtil.setContentView<ActivityClassificationBinding>(
         this,
         R.layout.activity_classification
     )
     ClassificationObservable.addObserver(this)
     ClassificationFinshObservable.addObserver(this)
     initView()
 }




 private fun initView() {
     tagAdapter = ClassificationTagAdapter(this)
     binding!!.rvClassify.layoutManager = LinearLayoutManager(this)
     binding!!.rvClassify.adapter = tagAdapter
     tagAdapter!!.setAsyncListDatas(tags)
     currentFragment = ClassificationContentFragment.newInstance(0)
     supportFragmentManager.beginTransaction().replace(R.id.fragment_content, currentFragment!!) .commit()

     tagAdapter!!.setOnViewClickListener(object :
         KtAdapter.OnAdapterViewClickListener<ClassificationTagInfo> {
         override fun onViewClick(v: View?, program: ClassificationTagInfo?) {
             var position = tagAdapter!!.getAsyncListItems()!!.indexOf(program)
             currentFragment!!.setData(getContentData(position), position)
             processFinish(position)
         }
     })
 }

 fun getContentData(position: Int): ArrayList<ClassificationContentInfo> {
     var contentInfos = ArrayList<ClassificationContentInfo>()
     var contentInfo = ClassificationContentInfo()
     contentInfo.title = tags.get(position).title
     contentInfo.imgs = imgs
     contentInfos.add(contentInfo)
     return contentInfos
 }

 override fun onDestroy() {
     super.onDestroy()
     ClassificationObservable.deleteObserver(this)
     ClassificationFinshObservable.deleteObserver(this)
 }

 //右侧刷新的观察者
 private fun processRefreshLoadMoreData(info: ClassificationObservableInfo) {
     if ((info.type == 0 && info.position == 0) || (info.type == 1 && info.position >= tags.size - 1)) {
         currentFragment!!.finish()
         return
     }
     if (info.type == 0) {
         //下拉 刷新
         info.position -= 1
     } else {
         //上拉加载
         info.position += 1
     }
     currentFragment!!.setData(getContentData(info.position),  info.position)
 }
 //刷新完成后改变 左侧标题数据
 private fun processFinish(position: Int) {
     var newList = ArrayList<ClassificationTagInfo>()
     var oldList = tagAdapter!!.getAsyncListItems()
     oldList.forEachIndexed { index, classificationTagInfo ->
         var info: ClassificationTagInfo? = null
         if (index == position) {
             info = ClassificationTagInfo(classificationTagInfo.title, true)
         } else {
             info = ClassificationTagInfo(classificationTagInfo.title, false)
         }
         newList.add(info)
     }
     tagAdapter!!.setAsyncListDatas(newList)
 }


 override fun update(o: Observable?, arg: Any?) {
     if (o is ClassificationObservable) {
         var info = arg as ClassificationObservableInfo
         processRefreshLoadMoreData(info)
     } else if (o is ClassificationFinshObservable) {
         processFinish(arg as Int)
     }
 }


}

1.2.layout

<?xml version="1.0" encoding="utf-8"?>
<layout>


    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_classify"
            android:layout_width="100dp"
            android:layout_height="wrap_content" />

        <FrameLayout
            android:id="@+id/fragment_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/rv_classify" />

    </RelativeLayout>

</layout>

2.右侧Fragment实现

package com.wu.third.classification

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener
import com.wu.third.R
import com.wu.third.databinding.FragmentClassificationContentBinding


/**
* @author wkq
*
* @date 2021年11月18日 16:06
*
*@des
*
*/

class ClassificationContentFragment : Fragment() {
  //设置出艰苦
  var imgs = arrayListOf<String>(
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F16%2F10%2F29%2F2ac8e99273bc079e40a8dc079ca11b1f.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=0b42192b10b6d521d58cd0650a0148e6",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F17%2F09%2F15%2F67351408baad11ce25c9b14166a049a6.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=a6c67c2f08b86a82348b2c87e75ffd9c",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Ftupian.qqjay.com%2Fu%2F2018%2F0222%2F2_163119_13.jpg&refer=http%3A%2F%2Ftupian.qqjay.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=995f87498f2d19ab6c885e09904d1ef3",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Ftupian.qqjay.com%2Fu%2F2018%2F0222%2F2_163119_13.jpg&refer=http%3A%2F%2Ftupian.qqjay.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=995f87498f2d19ab6c885e09904d1ef3",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Ftupian.qqjay.com%2Fu%2F2018%2F0222%2F2_163119_13.jpg&refer=http%3A%2F%2Ftupian.qqjay.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=995f87498f2d19ab6c885e09904d1ef3",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Ftupian.qqjay.com%2Fu%2F2018%2F0222%2F2_163119_13.jpg&refer=http%3A%2F%2Ftupian.qqjay.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=995f87498f2d19ab6c885e09904d1ef3",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fdpic.tiankong.com%2Ftc%2Feb%2FQJ9124407543.jpg&refer=http%3A%2F%2Fdpic.tiankong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=c76415814c9c52ae20480a89199a128c",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fitbbs%2F1705%2F10%2Fc35%2F46579542_1494425402317_mthumb.jpg&refer=http%3A%2F%2Fimg.pconline.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=3ddc7531c2a48fd48712346466ebd228",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp01%2F1ZZQ20QJS6-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639813297&t=5f6463e28700d48143f6be2c554f8a28"
  )
  var binding: FragmentClassificationContentBinding? = null
  var position = 0;
  var finisTime: Long = 1000

  companion object {
      fun newInstance(position: Int): ClassificationContentFragment {
          val args = Bundle()
          args.putInt("position", position)
          val fragment = ClassificationContentFragment()
          fragment.arguments = args
          return fragment
      }
  }

  override fun onCreateView(
      inflater: LayoutInflater,
      container: ViewGroup?,
      savedInstanceState: Bundle?
  ): View? {
      binding = DataBindingUtil.inflate<FragmentClassificationContentBinding>(
          layoutInflater,
          R.layout.fragment_classification_content, container, false
      )
      return binding!!.root
  }

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      super.onViewCreated(view, savedInstanceState)
      position = arguments!!.getInt("position")
      initData()
      initView()

  }

  var mContentInfos = ArrayList<ClassificationContentInfo>()
  var contentAdapter: ClassificationContentAdapter? = null
  private fun initData() {
      var contentInfo = ClassificationContentInfo()
      contentInfo.title = "家电"
      contentInfo.imgs = imgs
      mContentInfos.add(contentInfo)
  }

  private fun initView() {

      contentAdapter = ClassificationContentAdapter(activity!!);
      binding!!.rvContent.layoutManager = LinearLayoutManager(activity!!)
      binding!!.rvContent.adapter = contentAdapter
      contentAdapter!!.addItems(mContentInfos)

      binding!!.sfLayout.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener {
          override fun onRefresh(refreshLayout: RefreshLayout) {
              postRefreshLoadMore(0)
          }

          override fun onLoadMore(refreshLayout: RefreshLayout) {
              postRefreshLoadMore(1)
          }
      })
  }
  //延时执行刷新 为了保留 顶部和顶部的刷新布局
  fun postRefreshLoadMore(type: Int) {
      binding!!.sfLayout.postDelayed(object : Runnable {
          override fun run() {
              ClassificationObservable.update(ClassificationObservableInfo(type, position))
          }
      }, finisTime)

  }

  fun setData(contentInfos: ArrayList<ClassificationContentInfo>, position: Int) {
      this.position = position
      mContentInfos = contentInfos
      contentAdapter!!.setNewData(mContentInfos)
      ClassificationFinshObservable.update(position)
      finish()
  }

  fun finish() {
      binding!!.sfLayout.finishLoadMore()
      binding!!.sfLayout.finishRefresh()
      goTop()

  }

  //为了兼容一下 sfLayout 的定时问题 做了一下延时
  fun goTop() {
      binding!!.sfLayout.postDelayed(object : Runnable {
          override fun run() {
              binding!!.rvContent.scrollToPosition(0);
              var mLayoutManager = binding!!.rvContent.getLayoutManager() as LinearLayoutManager
              mLayoutManager.scrollToPositionWithOffset(0, 0);
          }
      }, 100)

  }


}

2.2 layout

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <com.scwang.smartrefresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/sf_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="@color/color_m_red"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="上拉加载上一页"
                android:textColor="@color/white" />

        </RelativeLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="@color/color_1aad19"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="下拉加载下一页"
                android:textColor="@color/white" />

        </RelativeLayout>


    </com.scwang.smartrefresh.layout.SmartRefreshLayout>

</layout>

3.左侧适配器

package com.wu.third.classification

import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.RecyclerView
import com.wu.base.adapter.KtAdapter
import com.wu.base.base.adapter.KtDataBindingViewHolder
import com.wu.third.R
import com.wu.third.databinding.LayoutClassficationTagBinding


/**
* @author wkq
*
* @date 2021年11月18日 14:55
*
*@des  左侧标题的Adapter
*
*/

class ClassificationTagAdapter(mContext: Context) : KtAdapter<ClassificationTagInfo>(mContext) {
  //DiffUtil  的异步刷新的工具
  var diff: AsyncListDiffer<ClassificationTagInfo>? = null

  init {
      this.mContext = mContext
      diff = AsyncListDiffer<ClassificationTagInfo>(this, ClassificationTagDiffItemCallBack())
  }


  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
      var binding = DataBindingUtil.inflate<LayoutClassficationTagBinding>(
          LayoutInflater.from(mContext),
          R.layout.layout_classfication_tag, parent, false
      )

      var holder = KtDataBindingViewHolder(binding.root)
      holder.binding = binding
      return holder
  }


  override fun onBindViewHolder(
      holder: RecyclerView.ViewHolder,
      position: Int,
      payloads: MutableList<Any>
  ) {
      // payloads  为null 整条数据刷新
      if (payloads.isEmpty() || payloads.size <= 0) {
          super.onBindViewHolder(holder, position, payloads)
      } else {
          //局部更新   不会更新整个item 更新指定的控件
          var bundle = payloads.get(0) as Bundle
          if (bundle != null) {
              var title = bundle.getString("title")
              var isShow = bundle.getBoolean("isShow")
              var holder = holder as KtDataBindingViewHolder
              var binding = holder.binding as LayoutClassficationTagBinding
              if (!TextUtils.isEmpty(title)) {
                  binding.tvTag.text = title
              }
              if (isShow) {
                  binding.rlRoot.setBackgroundColor(mContext.resources.getColor(R.color.color_23d41e))
              } else {
                  binding.rlRoot.setBackgroundColor(mContext.resources.getColor(R.color.white))
              }
          }
      }
  }

  override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
      var bindingHolder = holder as KtDataBindingViewHolder
      var binding = bindingHolder.binding as LayoutClassficationTagBinding
      binding.tvTag.text = getAsyncListItem(position)!!.title
      if (getAsyncListItem(position)!!.isShow) {
          binding.rlRoot.setBackgroundColor(mContext.resources.getColor(R.color.color_23d41e))
      } else {
          binding.rlRoot.setBackgroundColor(mContext.resources.getColor(R.color.white))
      }

      binding.rlRoot.setOnClickListener {
          if (viewClickListener!=null){
              viewClickListener!!.onViewClick( binding.rlRoot,getAsyncListItem(position))
          }
      }

  }

  fun setAsyncListDatas(newList: List<ClassificationTagInfo>) {
      if (diff == null) return
      diff!!.submitList(newList)
  }

  fun getAsyncListItem(position: Int): ClassificationTagInfo {
      return diff!!.currentList.get(position)
  }

  fun getAsyncListItems(): List<ClassificationTagInfo> {
      return diff!!.currentList
  }

  override fun getItemCount(): Int {
      return diff!!.currentList.size
  }


}

3.2 ClassificationTagDiffItemCallBack

package com.wu.third.classification

import android.os.Bundle
import android.text.TextUtils
import androidx.recyclerview.widget.DiffUtil


/**
 * @author wkq
 *
 * @date 2021年09月06日 14:33
 *
 *@des  异步差分对比的监听
 *
 */

class ClassificationTagDiffItemCallBack() :
    DiffUtil.ItemCallback<ClassificationTagInfo>() {

    //是否相同的id
    override fun areItemsTheSame(oldItem: ClassificationTagInfo, newItem: ClassificationTagInfo): Boolean {
        return oldItem.title!!.equals(oldItem.title)

    }
    //是否相同的数据
    override fun areContentsTheSame(oldItem: ClassificationTagInfo, newItem: ClassificationTagInfo): Boolean {
        var oldItem = oldItem.toString()
        var newItem = newItem.toString()
        return oldItem.equals(newItem)
    }


    //  局部刷新  返回null 整条数据刷新
    override fun getChangePayload(oldItem: ClassificationTagInfo, newItem: ClassificationTagInfo): Any? {
        var bundle = Bundle()
        // onBindViewHolder  实现三个参数  payloads   第一个数据为  封装的bundle
        if (!TextUtils.equals(oldItem.title, newItem.title)) {
            bundle.putString("title", newItem.title)
        }
        if (oldItem.isShow!=newItem.isShow) {
            bundle.putBoolean("isShow", newItem.isShow)
        }
        return bundle
    }


}

3.3右侧Adapter

package com.wu.third.classification

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.wu.base.adapter.KtAdapter
import com.wu.base.base.adapter.KtDataBindingViewHolder
import com.wu.third.R
import com.wu.third.databinding.ItemClassificationContentBinding


/**
 * @author wkq
 *
 * @date 2021年11月18日 15:03
 *
 *@des  右侧内容的Adapter
 *
 */

class ClassificationContentAdapter(mContext: Context) :
    KtAdapter<ClassificationContentInfo>(mContext) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        var binding = DataBindingUtil.inflate<ItemClassificationContentBinding>(
            LayoutInflater.from(mContext),
            R.layout.item_classification_content, parent, false
        )
        var holder = KtDataBindingViewHolder(binding.root)
        holder.binding = binding
        return holder
    }
    var binding:ItemClassificationContentBinding?=null
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        var bindingHolder = holder as KtDataBindingViewHolder
         binding = bindingHolder.binding as ItemClassificationContentBinding
        binding!!.tvTitle.text = getItem(position)!!.title
        binding!!.rvImgs.layoutManager = GridLayoutManager(mContext, 4)
        var adapter = ClassificationImgsAdapter(mContext)
        binding!!.rvImgs.adapter = adapter
        adapter.addItems(getItem(position)!!.imgs)
    }

    fun setNewData(newDatas:ArrayList<ClassificationContentInfo>){
        removeAllItems()
        itemList=newDatas
        notifyDataSetChanged()
        binding!!.rvImgs.scrollToPosition(0)
    }


}

新增:自定义LinearLayoutManager左侧分类自动居中逻辑

package com.wu.third.classification;

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;

/**
 * @author wkq
 * @date 2021年11月26日 16:57
 * @des
 */


public class CenterLinearLayoutManager extends LinearLayoutManager {

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

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

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

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

    private static class CenterSmoothScroller extends LinearSmoothScroller {

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

        @Override
        public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
            return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
        }

        //滚动速度
        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            return 400f / displayMetrics.densityDpi;
        }

    }

}

自动滑动到中间调用

        //自动滑动到中间
        centerLinearLayoutManager!!.smoothScrollToPosition(binding!!.rvClassify, RecyclerView.State(),position)

总结

大致逻辑代码就是这样,核心实现了 商品分类点击右侧切换数据,右侧商品分类滑动切换左侧商品分类的逻辑.商品右侧的分类实现了上拉 和下拉的一部分动画

资源

1. DiffUti局部刷新的介绍

2. DiffUti局部刷新的介绍(异步刷新)

3. 源码下载,欢迎Star

相关文章

网友评论

    本文标题:Android 仿京东分类功能实现

    本文链接:https://www.haomeiwen.com/subject/knzstrtx.html