1.需求背景:
需要实现类似淘宝,京东app分类主页的功能,左侧列表是一级标题,右侧展示二级标题和三级详细列表,右侧展示列表在底部继续上可以切换到下一个子分类信息,或者在顶部继续下拉切换到上一个子分类信息。
效果图如下:
三级数据数据模型如下:
{
"id":4,
"name":"美妆",
"sname":"美妆",
"level":0,
"parent_id":0,
"logo":null,
"children":[
{
"id":62,
"name":"彩妆",
"sname":"彩妆",
"level":1,
"parent_id":4,
"logo":"https://img.daff9.cn/biyingniao/images/other/1909/5d80d7d33d93a.jpg",
"children":[
{
"id":63,
"name":"彩妆套装",
"sname":"彩妆套装",
"level":2,
"parent_id":62,
"logo":"https://img.daff9.cn/biyingniao/images/other/1909/5d8b375dae870.jpg",
"children":[
]
}
]
}
]
}
2.实现思路:
布局文件中主要分三大块,顶部搜索框区域较为简单,暂时略过,底部分类主内容展示区域通过左侧一个recycleview将分类信息中的一级标题展示出来,右侧则通过scrollview不断添加二级分类和三级分类信息,scrollview中每一个子view都是顶部是二级分类标题,列表则是三级分类详细信息(标题和图片)。
scrollview子view实现如下:
category_right_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:descendantFocusability="blocksDescendants"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/right_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:textSize="14sp"
android:textColor="@color/category_main_title_unselect"
android:fontFamily="NotoSansCJKsc-Regular"
android:layout_marginTop="13dp"
android:layout_marginStart="10dp"
android:layout_marginBottom="11dp"
/>
<android.support.v7.widget.RecyclerView
android:id="@+id/right_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/right_item_title"
android:background="@drawable/cate_right_flex_bg"
android:paddingBottom="14dp"
/>
</RelativeLayout>
CategoryFlowView.java
public class CategoryFlowView extends LinearLayout {
private static final String TAG = "CategoryFlowView";
private Context context;
private RecyclerView boxLayout;
private TextView title;
private CategorySecondItemBean data;
public CategoryFlowView(Context context) {
this(context, null);
}
public CategoryFlowView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CategoryFlowView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CategoryFlowView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context cn) {
context = cn;
LayoutInflater inflater = LayoutInflater.from(cn);
View rootView = inflater.inflate(R.layout.category_right_item, this);
title = (TextView) rootView.findViewById(R.id.right_item_title);
boxLayout = (RecyclerView) rootView.findViewById(R.id.right_box);
}
public void setData(CategorySecondItemBean bean) {
this.data = bean;
title.setText(bean.getName());
List<CategoryThirdItemBean> children = bean.getChildren();
if (children != null && children.size() != 0) {
CategoryRecycleAdapter adapter = new CategoryRecycleAdapter(context, children);
GridLayoutManager layoutManager = new GridLayoutManager(context, 3) {
@Override
public boolean canScrollVertically() {
return false;
}
};
boxLayout.setLayoutManager(layoutManager);
boxLayout.setAdapter(adapter);
} else {
this.setVisibility(View.GONE);
}
}
}
ScrollView实现滑动到顶部或者底部后继续拉动产生回调事件,该功能通过重载onOverScrolled实现:
ScrollView.java中有代码如下:
@Override
public boolean onTouchEvent(MotionEvent ev) {
......
switch (actionMasked) {
case MotionEvent.ACTION_DOWN:
......
case MotionEvent.ACTION_MOVE:
......
如果是拖动的话
if (mIsBeingDragged) {
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
//调用overScrollBy将会调用onOverScrolled,它将会调用onScrollChanged如果适用的话
if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
&& !hasNestedScrollingParent()) {
......
}
...
自定义scrollview后重载onOverScrolled,测试中打印日志发现果然能够证明之前的猜想,到了顶部或者底部继续上下拉会调用该接口,遂自定义scrollview如下:
CouponScrollView.java
public class CouponScrollView extends ScrollView {
private OverScrollListener overScrollListener;
private int count = 0;
private boolean top,bottom,overScrolled;
public CouponScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setOverScrollListener(OverScrollListener listener) {
this.overScrollListener = listener;
}
public void init() {
count = 0;
top = false;
bottom = false;
overScrolled = false;
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
if(overScrollListener == null) {
return;
}
if(clampedY) {
count++;
} else {
count=0;
}
if(count == 6) {
overScrolled = true;
if(scrollY == 0) {
//滑动到了顶部
top = true;
bottom = false;
} else {
//滑动到了底部
top = false;
bottom = true;
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (overScrollListener != null && overScrolled) {
overScrolled = false;
overScrollListener.overScrolled(top,bottom);
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
public interface OverScrollListener {
void overScrolled(boolean top, boolean bottom);
}
}
剩下的功能就是从网上或者本地文件中读取分类信息,将分类信息分别填充到左侧的一级标题recycleview中,和填充到CategoryFlowView然后添加到右侧的scrollview中,
完整代码如下:
https://github.com/teng89/category