仿电商商品分类的思路实现

仿电商商品分类的思路实现

引言

按照以前的习惯,本来是每周一篇,因为昨天去逛街买了条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();
        }
    });

原文发布于微信公众号 - codelang(codelang)

原文发表时间:2017-11-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏pangguoming

Spring Boot集成JasperReports生成PDF文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲...

1.2K7
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

4878
来自专栏我和未来有约会

Kit 3D 更新

Kit3D is a 3D graphics engine written for Microsoft Silverlight. Kit3D was inita...

2586
来自专栏落花落雨不落叶

canvas画简单电路图

63311
来自专栏菩提树下的杨过

Flash/Flex学习笔记(23):运动学原理

先写一个公用的小球类Ball: package{ import flash.display.Sprite; //小球 类 public class B...

25410
来自专栏一个会写诗的程序员的博客

Spring Reactor 项目核心库Reactor Core

Non-Blocking Reactive Streams Foundation for the JVM both implementing a Reactiv...

2192
来自专栏我和未来有约会

Silverlight第三方控件专题

这里我收集整理了目前网上silverlight第三方控件的专题,若果有所遗漏请告知我一下。 名称 简介 截图 telerik 商 RadC...

4045
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3195
来自专栏芋道源码1024

熔断器 Hystrix 源码解析 —— 断路器 HystrixCircuitBreaker

本文主要基于 Hystrix 1.5.X 版本 1. 概述 2. HystrixCircuitBreaker 3. HystrixCircuitBreaker....

5367
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

2717

扫码关注云+社区