仿电商商品分类的思路实现
引言
按照以前的习惯,本来是每周一篇,因为昨天去逛街买了条169的裤子给耽误了,周一早上来补上。
丑豆很早就让我给他写一下这个demo,每次都有点忙没给他写,趁着昨天晚上睡前一小时来搞定。
效果图
我参照的是拼多多商品分类的界面来写的,先看看样图
然后看看动态的效果图
实现思路
这个页面用了两个并排的列表,右边列表每个item都有一个type对应左边的列表item的每一个type,右边的列表在滑动的时候,左边的列表选择也会跟着变化,在右边的列表一直往上滑或是往下滑的时候,左边的列表item对应的type并没有显示在界面的话,我们还需要左边的列表进行一个滚动到对应的item的位置上,知道思路了,然后我们开始敲代码
布局代码实现
1、 主布局是两个列表,这两个列表我通过LineaLayout的weight进行了一个平分
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="dingshi.com.tworecycleview.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/main_left_recycle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />
<android.support.v7.widget.RecyclerView
android:id="@+id/main_right_recycle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="7" />
</LinearLayout>
2、左边列表的layout我就不贴了,就是一个TextView和ImageView的事
3、右边列表的layout我重写了RecycleView的onMeasure方法,使其能扩展到最大,如果直接使用RecycleView的话,会导致界面显示不完全,而且还可以滑动,这是不允许的。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="wrap_content"
android:background="#fff"
android:padding="10dp">
<TextView
android:id="@+id/item_main_right_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="鞋包"
android:textColor="#333"
android:textSize="17dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="查看更多 >"
android:textColor="#999"
android:textSize="13dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<dingshi.com.tworecycleview.AbsoluteRecycleView
android:id="@+id/item_main_right_recycle"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/item_main_right_type" />
</android.support.constraint.ConstraintLayout>
重写的RecycleView
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
public class AbsoluteRecycleView extends RecyclerView {
public AbsoluteRecycleView(Context context) {
super(context);
}
public AbsoluteRecycleView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
主界面代码实现
1、参数的定义
WQRecycleAdapter是自己封装的一个通用的Adapter,让你的项目只存在一个adapter。
public class MainActivity extends AppCompatActivity {
RecyclerView leftRecycle;
RecyclerView rightRecycle;
WQRecycleAdapter leftAdapter;
WQRecycleAdapter rightAdapter;
/**
* 存储左边列表内容
*/
List<String> leftList = new ArrayList<>();
/**
* 存储右边列表对应左边列表的type
*/
List<String> rightList = new ArrayList<>();
/**
* 右边列表item的内容
*/
List<String> detailsList = new ArrayList<>();
/**
* 记录当前在哪个position位置
*/
int currentPosition = 0;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
leftRecycle = (RecyclerView) findViewById(R.id.main_left_recycle);
rightRecycle = (RecyclerView) findViewById(R.id.main_right_recycle);
leftRecycle.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
rightRecycle.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
leftAdapter = new WQRecycleAdapter(this, R.layout.item_main_left, leftList);
leftRecycle.setAdapter(leftAdapter);
rightAdapter = new WQRecycleAdapter(this, R.layout.item_main_right, rightList);
rightRecycle.setAdapter(rightAdapter);
...
}
/**
* 初始化数据源
*/
private void initData() {
for (int i = 0; i < 20; i++) {
leftList.add("" + i);
rightList.add("" + i);
}
for (int i = 0; i < 9; i++) {
detailsList.add("");
}
}
}
2、设置两个adapter的数据填充
/**
* 左边item填充数据
*/
leftAdapter.setCallBack(new WQRecycleAdapter.CallBack() {
@Override
public <T> void convert(WQViewHolder holder, T bean, int position) {
LinearLayout layout = (LinearLayout) holder.getView(R.id.item_main_left_layout);
extView type = (TextView) holder.getView(R.id.item_main_left_type);
type.setText((String) bean);
if (position == currentPosition) {
layout.setBackgroundColor(0xffffffff);
type.setTextColor(getResources().getColor(R.color.colorAccent));
} else {
layout.setBackgroundColor(0xffeeeeee);
type.setTextColor(0xff444444);
}
}
});
/**
* 右边item填充数据
*/
rightAdapter.setCallBack(new WQRecycleAdapter.CallBack() {
@Override
public <T> void convert(WQViewHolder holder, T bean, int position) {
holder.setText(R.id.item_main_right_type, (String) bean);
RecyclerView detailsRecycle = (RecyclerView) holder.getView(R.id.item_main_right_recycle);
updateDetailsRecycle(detailsRecycle);
}
});
/**
* 右边列表的详情
* 使用GridLayoutManager来生成3列的网格布局
* @param detailsRecycle
*/
public void updateDetailsRecycle(RecyclerView detailsRecycle) {
WQRecycleAdapter detailsAdapter = new WQRecycleAdapter(this, R.layout.item_main_details, detailsList);
detailsRecycle.setLayoutManager(new GridLayoutManager(this, 3));
detailsRecycle.setAdapter(detailsAdapter);
}
3、设置左边adapter的点击事件
/**
* 左边列表item的点击事件
* 拿到左边item的position让右边的item跳转到指定的position
*/
leftAdapter.setOnItemClickListner(new WQRecycleAdapter.OnItemClickListner() {
@Override
public void onItemClickListner(View v, int position) {
LinearLayoutManager llm = ((LinearLayoutManager) rightRecycle.getLayoutManager());
llm.scrollToPositionWithOffset(position, 0);
}
});
4、右边RecycleView的滑动监听
这个部分是重中之中,我们先来想想右边滑动我们需要做哪些事:
- 获取右边列表第一个item处于在第几个position,将这个position设置到左边的列表,控制左边列表的变化
- 上面的条件会有一个弊端,如果左边列表只显示10个类型,右边的列表已经滑动到第11个item了,那左边的列表因为被隐藏而看不到效果,这时候,我们需要去滚动左边的列表
- 判断处理:
①、如果左边列表的第一个item的position大于右边列表滚动的position的话,我们需要左边的列表进行向上滚动处理,这个处理很简单,只需要让左边的列表scrollToPositionWithOffset到右边列表的position,
②、如果左边列表的最后一个item的position小于右边列表滚动的position的话,我们需要左边的列表进行向下滚动处理,这个处理跟上面一样,拿到右边的position,是左边的列表scrollToPositionWithOffset到对应的位置
- 滑动到底部的处理:
因为我只判断右边第一个item出现来设置左边的position,如果右边列表的type过于拥挤的话,滑动到底部的时候,左边的列表并不会选中到最后一个item,这时候,我们需要判断,如果右边列表滑动到底部的话,则设置左边选中的position为数据集合的长度减1
实现代码
/**
* 右边滑动的监听事件
*/
rightRecycle.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
LinearLayoutManager rightManager = (LinearLayoutManager) rightRecycle.getLayoutManager();
LinearLayoutManager leftManager = ((LinearLayoutManager) leftRecycle.getLayoutManager());
/**
* 获取第一个item为第几个position
*/
currentPosition = rightManager.findFirstVisibleItemPosition();
/**
* 这地方需要进行判断,如果右边的Recycle在移动的时候,左边的RecycleView也是需要进行移动的
* 左边的recycleview有可能会不可见,这时候,我们必须去判断一下,左边最后的一个item是不是
* 小于右边滑动的位置,或左边第一个item是不是大于右边滑动的位置
*/
if (leftManager.findFirstVisibleItemPosition() > currentPosition) {
leftManager.scrollToPositionWithOffset(currentPosition, 0);
} else if (leftManager.findLastVisibleItemPosition() < currentPosition) {
leftManager.scrollToPositionWithOffset(currentPosition, 0);
}
/**
* 判断右边是否滑动到最后一个item,是的话,也将左边移动到最后一个item
* canScrollVertically(1)表示是否能向上滚动,false表示已经滚动到底部
*/
if (!rightRecycle.canScrollVertically(1)) {
currentPosition = rightList.size() - 1;
}
/**
* 更新左边列表
*/
leftAdapter.notifyDataSetChanged();
}
});
总结
代码量并不多,实现思路也很简单,都是平常使用到的方法,最后还要提一个,在我们项目实施的过程中,不能一味的寻找框架和copy来解决问题,学会思考问题才是关键,项目已经上传到github,下载链接:https://github.com/MRwangqi/Mall_classify
最近项目有接上微信分享、登录、支付和支付宝支付,由于微信的结果处理都必须在指定类里面去处理,为了使开放方便,刚开发了一套特别Easy化的封装,先贴一小段使用代码,由于没投入到生产环境,先不把代码共享出来,我先看看会不会有bug出现,预计这个礼拜六把思路和代码整理出来分享给大家
PayWeixin payWeixin = new PayWeixin();
payWeixin.setAppid("");
payWeixin.setNoncestr("");
payWeixin.setPackag("");
payWeixin.setPartnerid("");
payWeixin.setPrepayid("");
payWeixin.setSign("");
payWeixin.setTimestamp("");
payWeixin.setOrdercode("");
EasyPayShare.getInstance().doPayWx(mActivity, payWeixin, new ShareCallBack() {
@Override
public void onSuccess(String result) {
Toast.makeText(activity, "支付成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onCanceled(String result) {
Toast.makeText(activity, "支付取消", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailed(String result) {
Toast.makeText(activity, "支付失败", Toast.LENGTH_SHORT).show();
}
});
ShareParams params = new ShareParams.Build()
.withDescribe("aa")
.withTitle("hahah")
.withUrl("http://www.baidu.com")
.withShareType(IWeixin.WXSceneSession)
.build();
EasyPayShare.getInstance().doShareWx(mActivity, params, new ShareCallBack() {
@Override
public void onSuccess(String result) {
Toast.makeText(activity, "分享成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onCanceled(String result) {
Toast.makeText(activity, "取消分享", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailed(String result) {
Toast.makeText(activity, "分享失败", Toast.LENGTH_SHORT).show();
}
});