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

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

引言

按照以前的习惯,本来是每周一篇,因为昨天去逛街买了条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 条评论
登录 后参与评论

相关文章

来自专栏数据小魔方

让执着成为一种习惯——仿网易数独玫瑰气泡图

没有难学的技艺,只有不够辛勤的付出! 今天这篇文章推送仿的的是网易数独的一幅信息图,内容呈现的是全球各国人民对于养老所持的态度,数据来源于Pew Reserch...

3735
来自专栏技术之路

Caliburn.Micro学习笔记(五)----协同IResult

今天说一下协同IResult 看一下IResult接口 /// <summary> /// Allows custom code to execute...

1848
来自专栏学海无涯

Android开发之那些好用的数据结构与API(三)

之前的系列文章 Android开发之那些好用的数据结构与API 和Android开发之那些好用的数据结构与API(二)中,已经介绍了一些,趁热打铁,本次介绍的内...

32411
来自专栏好好学java的技术栈

特别的520,送给特别的你们,还不来看看?

782
来自专栏Android中高级开发

Android开发之漫漫长途 番外篇——自定义View的各种姿势2

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

773
来自专栏HTML5学堂

一步步教你弹性框架-中篇

HTML5学堂:本文继续为大家讲解弹性框架,在前一篇文章当中,我们实现了最基本的来回运动,在本文当中我们将基于前者,继续书写我们的代码。主要包括缓冲效果、有摩擦...

3364
来自专栏iOS技术

iOS 无侵入实现段落样式控制(解决富文本单行显示中文问题)

在iOS开发中,文本格式(富文本)处理是一个比较麻烦的问题(我们姑且说它是麻烦的)。这里我提两点比较蛋疼的地方:

2644
来自专栏JackieZheng

漫谈可视化Prefuse(五)---一款属于我自己的可视化工具

  伴随着前期的基础积累,翻过API,读过一些Demo,总觉得自己已经摸透了Prefuse,小打小闹似乎已经无法满足内心膨胀的自己。还记得儿时看的《武状元苏乞儿...

2368
来自专栏Python攻城狮

Markdown-认识与使用1.简介2.使用一级标题3.设置Markdown编辑

Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用。看到这里请不要被「标记」、「语言」所迷惑,Markdo...

601
来自专栏我有一个梦想

Python 项目实践一(外星人入侵小游戏)第三篇

接着上节的继续学习, 一 重构:模块game_functions 在大型项目中,经常需要在添加新代码前重构既有代码。重构旨在简化既有代码的结构,使其更容易扩展。...

2169

扫码关注云+社区