安卓高仿京东分类页

前言

网购已经成为我们生活的一般,经常用的京东、淘宝等app,接到一个需求,开发电商app的分类页,这里写了个demo,高仿京东的分类页,我们看下效果

思路

顶部: 封住一个组件,这里不介绍

左侧: 一个RecyclerView即可,比较简单,这里也不介绍,想了解的直接看源码

右侧: TabLayout + RecyclerView 布局, 难点: tabLayout滚动RecyclerView到指定位置,滚动RecyclerView时,默认选中tabLayout

右侧布局

android:id="@+id/rightLinearLayoutCompat"

app:layout_behavior="@string/appbar_scrolling_view_behavior"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/tabLayout"

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:tabMode="scrollable"

app:tabIndicatorHeight="0dp"

app:tabMaxWidth="120dp"

app:tabMinWidth="60dp"

app:tabRippleColor="@color/transparent"

app:tabTextAppearance="@style/tab_title"

app:tabTextColor="@color/color_404040"

app:tabSelectedTextColor="@color/color_E33A3C"

app:tabBackground="@drawable/selector_tab_indicator2"/>

android:id="@+id/categoryRecyclerView"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

R.layout.main_right_grid_header

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:id="@+id/textHeader"

android:padding="@dimen/dp_4"

android:textColor="#181818"

android:textSize="14dp"

android:textStyle="bold"

android:text="专属推荐"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

R.layout.main_right_grid

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="100dp"

android:gravity="center">

android:id="@+id/thirdCategoryIcon"

android:layout_width="60dp"

android:layout_height="60dp"

android:scaleType="fitXY"/>

android:id="@+id/text_content"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textSize="12dp"

android:textColor="#898989"

android:text="男装馆"

android:layout_marginTop="10dp"/>

TabLayout addTab

tabLayout.removeAllTabs()

data.cateList.forEach { v -> tabLayout.addTab(tabLayout.newTab().setText(v.categoryName)) }

RecyclerView的adapter

package com.aries.category.ui.adapter

import android.widget.ImageView

import coil.load

import com.chad.library.adapter.base.BaseSectionQuickAdapter

import com.chad.library.adapter.base.viewholder.BaseViewHolder

import com.aries.category.R

import com.aries.category.ui.modal.CategoryModal

import com.aries.common.util.CoilUtil

class SectionQuickAdapter(sectionHeadResId: Int, layoutResId: Int, data: MutableList ):

BaseSectionQuickAdapter(sectionHeadResId, layoutResId, data) {

private var imageLoader = CoilUtil.getImageLoader()

override fun convertHeader(helper: BaseViewHolder, item: CategoryModal) {

helper.setText(R.id.textHeader, item.categoryName)

}

override fun convert(holder: BaseViewHolder, item: CategoryModal) {

holder.getView(R.id.thirdCategoryIcon).load(item.iconUrl, imageLoader ) {

crossfade(true)

placeholder(R.drawable.default_img)

error(R.drawable.default_img)

}

holder.setText(R.id.text_content, item.categoryName)

}

}

设置RecyclerView的 adapter 和 layoutManager

gridLayoutManager = GridLayoutManager(context, 3)

sectionQuickAdapter = SectionQuickAdapter(R.layout.main_right_grid_header, R.layout.main_right_grid, arrayListOf())

val thisTabLayout = tabLayout

categoryRecyclerView.run {

layoutManager = gridLayoutManager

adapter = sectionQuickAdapter

}

设置数据

val list: ArrayList = arrayListOf()

data.cateList.forEach { v ->

run {

list.add(CategoryModal(v.iconUrl, v.categoryName, v.categoryCode, true))

v.cateList?.forEach { m -> list.add(CategoryModal(m.iconUrl, m.categoryName, m.categoryCode, false))}

}

}

sectionQuickAdapter.setList(list)

重点: 设置 tabLayout 和 RecyclerView 联动关系

categoryRecyclerView.run {

setOnTouchListener { _, p1 ->

if (p1.action == MotionEvent.ACTION_DOWN) {

isRecyclerScroll = true

}

false

}

addOnScrollListener(object : RecyclerView.OnScrollListener(){

override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {

super.onScrolled(recyclerView, dx, dy)

if (isRecyclerScroll) {

val position = findHeaderPositionByTab(gridLayoutManager.findFirstVisibleItemPosition())

if (position != lastPos) {

thisTabLayout.setScrollPosition(position, 0F, true)

}

lastPos = position

}

}

override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {

super.onScrollStateChanged(recyclerView, newState)

if (mShouldScroll) {

mShouldScroll = false

scrollTop(mToPosition)

}

}

})

}

tabLayout.run {

addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener{

override fun onTabSelected(tab: TabLayout.Tab?) {

val position = tab?.position

if (position != null) {

scrollRecycleView2Top(position)

}

isRecyclerScroll = false

}

override fun onTabUnselected(tab: TabLayout.Tab?) {}

override fun onTabReselected(tab: TabLayout.Tab?) {}

})

}

private fun scrollTop(position: Int) {

val firstPosition = gridLayoutManager.findFirstVisibleItemPosition()

val lastPosition = gridLayoutManager.findLastVisibleItemPosition()

if (position < firstPosition) {

// 如果跳转位置在第一个可见位置之前,就smoothScrollToPosition可以直接跳转

categoryRecyclerView.smoothScrollToPosition(position)

} else if (position <= lastPosition){

// 跳转位置在第一个可见项之后,最后一个可见项之前

// smoothScrollToPosition根本不会动,此时调用smoothScrollBy来滑动到指定位置

val movePosition = position - firstPosition

if (movePosition >=0 && movePosition < categoryRecyclerView.childCount) {

val scrollY = categoryRecyclerView.getChildAt(position - firstPosition).top

categoryRecyclerView.smoothScrollBy(0, scrollY)

}

} else {

// 如果要跳转的位置在最后可见项之后,则先调用smoothScrollToPosition将要跳转的位置滚动到可见位置

// 再通过onScrollStateChanged控制再次调用smoothMoveToPosition,执行上一个判断中的方法

categoryRecyclerView.smoothScrollToPosition(position)

mToPosition = position

mShouldScroll = true

}

}

private fun scrollRecycleView2Top(position: Int) {

val currentItem = dataCopy.cateList[position]

val currentPosition = sectionQuickAdapter.data.indexOfFirst { v -> v.categoryCode == currentItem.categoryCode }

scrollTop(currentPosition)

}

结束语

 目前专注于前端⚙️ 在react、react-native开发方面有丰富的经验 最近在学习安卓,有自己的开源安卓项目,集成react-native热更新功能我❤️ 思考、学习、编码和健身如果文章对您有帮助,三连支持一下~O(∩_∩)O谢谢!

相关链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。