先上效果图

淘宝首页是从上到下是各种不同的样式,最上面是搜索,其次是一个轮播图,再下来是10个圆角的菜单,等等,我们可以采用一个recyclerView实现,但是实现起来的复杂程度是比较高的,如果使用阿里开源的VLayout控件,实现起来则简单多了,Vlayout就适用于这种多种item的布局。

官方文档

详细的介绍可以参考官网文档,中文版:https://github.com/alibaba/vlayout/blob/master/README-ch.md

代码实现

先来看主页面的xml布局,为了简单把搜索栏用图片代替,下面是一个RecyclerView

<?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"android:orientation="vertical"tools:context=".MainActivity"><ImageViewandroid:layout_width="match_parent"android:layout_height="48dp"android:scaleType="centerCrop"android:src="@mipmap/img_title_bar" /><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

完了我们对recyclerView先进行初始化,设置LayoutManager,平时我们使用的系统自带的,这里我们使用VirtualLayoutManager,并设置回收复用池大小,(如果一屏内相同类型的 View 个数比较多,需要设置一个合适的大小,防止来回滚动时重新创建 View)。

        recyclerView = findViewById(R.id.rv);VirtualLayoutManager virtualLayoutManager = new VirtualLayoutManager(this);recyclerView.setLayoutManager(virtualLayoutManager);RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();viewPool.setMaxRecycledViews(0, 10);recyclerView.setRecycledViewPool(viewPool);

完了就到了加载数据的地方,正常的adaper是继承recyclerView的adapter,使用VLayout的话就要继承BaseDelegeteAdapter,可以像平常一样写继承自DelegateAdapter.Adapter的Adapter, 只比之前的Adapter需要多重载onCreateLayoutHelper方法。 其他的和默认Adapter一样。


public class BaseDelegeteAdapter extends DelegateAdapter.Adapter<BaseViewHolder> {private LayoutHelper mLayoutHelper;private int mCount = -1;private int mLayoutId = -1;private int mViewTypeItem = -1;public BaseDelegeteAdapter(LayoutHelper layoutHelper, int layoutId, int count) {this.mLayoutHelper = layoutHelper;this.mCount = count;this.mLayoutId = layoutId;}@Overridepublic LayoutHelper onCreateLayoutHelper() {return mLayoutHelper;}@NonNull@Overridepublic BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false));}@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {}@Overridepublic int getItemCount() {return mCount;}
}

ViewHolder的写法还和之前的一样


public class BaseViewHolder  extends RecyclerView.ViewHolder {private SparseArray<View> views;public BaseViewHolder(@NonNull View itemView) {super(itemView);this.views = new SparseArray<>();}public BaseViewHolder setTextColor(@IdRes int viewId, @ColorInt int textColor) {TextView view = getView(viewId);view.setTextColor(textColor);return this;}public BaseViewHolder setImageResource(@IdRes int viewId, @DrawableRes int imageResId) {ImageView view = getView(viewId);view.setImageResource(imageResId);return this;}public BaseViewHolder setText(@IdRes int viewId, CharSequence value) {TextView view = getView(viewId);view.setText(value);return this;}public <T extends View> T getView(@IdRes int viewId) {View view = views.get(viewId);if (view == null) {view = itemView.findViewById(viewId);views.put(viewId, view);}return (T) view;}
}

到这里跟之前其实都差不多,都是一些初始化的工作,接下来就加载数据了。先是第一个是轮播图,这里使用开源框架 implementation 'com.youth.banner:banner:1.4.10',我们先来创建Banner轮播图的adapter,因为其只有一个元素,所以我们使用LinearLayoutHelper: 线性布局就可以

    private BaseDelegeteAdapter getBannerAdapter() {return new BaseDelegeteAdapter(new LinearLayoutHelper(), R.layout.vlayout_banner, 1) {@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("https://img.alicdn.com/tps/TB1EMhjIpXXXXaPXVXXXXXXXXXX.jpg");arrayList.add("https://img.alicdn.com/simba/img/TB17OFBloD1gK0jSZFGSuvd3FXa.jpg");arrayList.add("https://img.alicdn.com/tfs/TB1HSHMlKH2gK0jSZJnXXaT1FXa-520-280.jpg");arrayList.add("https://img.alicdn.com/simba/img/TB181dplkL0gK0jSZFxSutWHVXa.jpg");arrayList.add("https://img.alicdn.com/simba/img/TB1rWhyleH2gK0jSZFESuwqMpXa.jpg");arrayList.add("https://img.alicdn.com/tfs/TB15xIZk7T2gK0jSZFkXXcIQFXa-520-280.png");// 绑定数据Banner mBanner = holder.getView(R.id.banner);//设置banner样式mBanner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR);//设置图片加载器mBanner.setImageLoader(new ImageLoader() {@Overridepublic void displayImage(Context context, Object path, ImageView imageView) {Glide.with(context).load(path).into(imageView);}});//设置图片集合mBanner.setImages(arrayList);//设置banner动画效果mBanner.setBannerAnimation(Transformer.DepthPage);//设置标题集合(当banner样式有显示title时)//        mBanner.setBannerTitles(titles);//设置自动轮播,默认为truemBanner.isAutoPlay(true);//设置轮播时间mBanner.setDelayTime(3000);//设置指示器位置(当banner模式中有指示器时)mBanner.setIndicatorGravity(BannerConfig.CENTER);//banner设置方法全部调用完毕时最后调用mBanner.start();}};}

接下来是10个按钮菜单,这里是上面5个,下面5个,我们采用GridLayoutHelper: Grid布局, 支持横向的colspan

    private BaseDelegeteAdapter getMenuAdapter() {GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(5);gridLayoutHelper.setPadding(0, 16, 0, 0);gridLayoutHelper.setVGap(10);gridLayoutHelper.setHGap(0); 控制子元素之间的水平间距return new BaseDelegeteAdapter(gridLayoutHelper, R.layout.vlayout_menu, 10) {@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, final int position) {holder.setText(R.id.tv_menu_title_home, ITEM_NAMES[position] + "");holder.setImageResource(R.id.iv_menu_home, IMG_URLS[position]);holder.getView(R.id.ll_menu_home).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(getApplicationContext(), ITEM_NAMES[position], Toast.LENGTH_SHORT).show();}});}};}

在接下来是两个竖直拍的新闻推送,滚动的文字我们也使用开源框架MarqueeView,我们使用LinearLayoutHelper: 线性布局

    private BaseDelegeteAdapter getNewsAdapter() {return new BaseDelegeteAdapter(new LinearLayoutHelper(), R.layout.vlayout_news, 1) {@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, int i) {MarqueeView marqueeView1 = holder.getView(R.id.marqueeView1);MarqueeView marqueeView2 = holder.getView(R.id.marqueeView2);List<String> info1 = new ArrayList<>();info1.add("天猫超市最近发大活动啦,快来抢");info1.add("没有最便宜,只有更便宜!");List<String> info2 = new ArrayList<>();info2.add("这个是用来搞笑的,不要在意这写小细节!");info2.add("啦啦啦啦,我就是来搞笑的!");marqueeView1.startWithList(info1);marqueeView2.startWithList(info2);// 在代码里设置自己的动画marqueeView1.startWithList(info1, R.anim.anim_bottom_in, R.anim.anim_top_out);marqueeView2.startWithList(info2, R.anim.anim_bottom_in, R.anim.anim_top_out);marqueeView1.setOnItemClickListener(new MarqueeView.OnItemClickListener() {@Overridepublic void onItemClick(int position, TextView textView) {Toast.makeText(getApplicationContext(), textView.getText().toString(), Toast.LENGTH_SHORT).show();}});marqueeView2.setOnItemClickListener(new MarqueeView.OnItemClickListener() {@Overridepublic void onItemClick(int position, TextView textView) {Toast.makeText(getApplicationContext(), textView.getText().toString(), Toast.LENGTH_SHORT).show();}});}};}

以此类推,后面的Adapter就不写了,得到各种adapter之后我们需要创建一个DelegateAdapter,并将各种adapter添加到DelegateAdapter,最后给recycler设置adapter设置DelegateAdapter就ok了

        BaseDelegeteAdapter bannerAdapter = getBannerAdapter();BaseDelegeteAdapter menuAdapter = getMenuAdapter();BaseDelegeteAdapter newsAdapter = getNewsAdapter();DelegateAdapter delegateAdapter = new DelegateAdapter(virtualLayoutManager, true);delegateAdapter.addAdapter(bannerAdapter);delegateAdapter.addAdapter(menuAdapter);delegateAdapter.addAdapter(newsAdapter);for (int i = 0; i < ITEM_URL.length; i++) {final int finalI = i;BaseDelegeteAdapter titleAdapter = getTitleAdapter(ITEM_URL[finalI]);GridLayoutHelper gridHelper = new GridLayoutHelper(2);BaseDelegeteAdapter gridAdapter = getGridAdapter(gridHelper);delegateAdapter.addAdapter(titleAdapter);delegateAdapter.addAdapter(gridAdapter);}recyclerView.setAdapter(delegateAdapter);

VLayout的使用就是这么简单,实现复杂的recyclerview布局,下面有MainActivity完整代码,文末附上Demo地址


public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;//应用String[] ITEM_NAMES = {"天猫", "聚划算", "天猫国际", "外卖", "天猫超市", "充值中心", "飞猪旅行", "领金币", "拍卖", "分类"};int[] IMG_URLS = {R.mipmap.ic_tian_mao, R.mipmap.ic_ju_hua_suan, R.mipmap.ic_tian_mao_guoji, R.mipmap.ic_waimai, R.mipmap.ic_chaoshi, R.mipmap.ic_voucher_center, R.mipmap.ic_travel, R.mipmap.ic_tao_gold, R.mipmap.ic_auction, R.mipmap.ic_classify};//    高颜值商品位int[] ITEM_URL = {R.mipmap.item1, R.mipmap.item2, R.mipmap.item3, R.mipmap.item4, R.mipmap.item5};int[] GRID_URL = {R.mipmap.flashsale1, R.mipmap.flashsale2, R.mipmap.flashsale3, R.mipmap.flashsale4};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {recyclerView = findViewById(R.id.rv);VirtualLayoutManager virtualLayoutManager = new VirtualLayoutManager(this);recyclerView.setLayoutManager(virtualLayoutManager);RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();viewPool.setMaxRecycledViews(0, 10);recyclerView.setRecycledViewPool(viewPool);BaseDelegeteAdapter bannerAdapter = getBannerAdapter();BaseDelegeteAdapter menuAdapter = getMenuAdapter();BaseDelegeteAdapter newsAdapter = getNewsAdapter();DelegateAdapter delegateAdapter = new DelegateAdapter(virtualLayoutManager, true);delegateAdapter.addAdapter(bannerAdapter);delegateAdapter.addAdapter(menuAdapter);delegateAdapter.addAdapter(newsAdapter);for (int i = 0; i < ITEM_URL.length; i++) {final int finalI = i;BaseDelegeteAdapter titleAdapter = getTitleAdapter(ITEM_URL[finalI]);GridLayoutHelper gridHelper = new GridLayoutHelper(2);BaseDelegeteAdapter gridAdapter = getGridAdapter(gridHelper);delegateAdapter.addAdapter(titleAdapter);delegateAdapter.addAdapter(gridAdapter);}recyclerView.setAdapter(delegateAdapter);}private BaseDelegeteAdapter getGridAdapter(final GridLayoutHelper gridHelper) {return new BaseDelegeteAdapter(gridHelper, R.layout.vlayout_grid, 4) {@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, final int position) {int item = GRID_URL[position];ImageView iv = holder.getView(R.id.iv);Glide.with(getApplicationContext()).load(item).into(iv);iv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(getApplicationContext(), "item" + position, Toast.LENGTH_SHORT).show();}});}};}private BaseDelegeteAdapter getTitleAdapter(final int imageResId) {return new BaseDelegeteAdapter(new LinearLayoutHelper(), R.layout.vlayout_title, 1) {@Overridepublic void onBindViewHolder(BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position);holder.setImageResource(R.id.iv, imageResId);}};}private BaseDelegeteAdapter getBannerAdapter() {return new BaseDelegeteAdapter(new LinearLayoutHelper(), R.layout.vlayout_banner, 1) {@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("https://img.alicdn.com/tps/TB1EMhjIpXXXXaPXVXXXXXXXXXX.jpg");arrayList.add("https://img.alicdn.com/simba/img/TB17OFBloD1gK0jSZFGSuvd3FXa.jpg");arrayList.add("https://img.alicdn.com/tfs/TB1HSHMlKH2gK0jSZJnXXaT1FXa-520-280.jpg");arrayList.add("https://img.alicdn.com/simba/img/TB181dplkL0gK0jSZFxSutWHVXa.jpg");arrayList.add("https://img.alicdn.com/simba/img/TB1rWhyleH2gK0jSZFESuwqMpXa.jpg");arrayList.add("https://img.alicdn.com/tfs/TB15xIZk7T2gK0jSZFkXXcIQFXa-520-280.png");// 绑定数据Banner mBanner = holder.getView(R.id.banner);//设置banner样式mBanner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR);//设置图片加载器mBanner.setImageLoader(new ImageLoader() {@Overridepublic void displayImage(Context context, Object path, ImageView imageView) {Glide.with(context).load(path).into(imageView);}});//设置图片集合mBanner.setImages(arrayList);//设置banner动画效果mBanner.setBannerAnimation(Transformer.DepthPage);//设置标题集合(当banner样式有显示title时)//        mBanner.setBannerTitles(titles);//设置自动轮播,默认为truemBanner.isAutoPlay(true);//设置轮播时间mBanner.setDelayTime(3000);//设置指示器位置(当banner模式中有指示器时)mBanner.setIndicatorGravity(BannerConfig.CENTER);//banner设置方法全部调用完毕时最后调用mBanner.start();}};}private BaseDelegeteAdapter getMenuAdapter() {GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(5);gridLayoutHelper.setPadding(0, 16, 0, 0);gridLayoutHelper.setVGap(10);gridLayoutHelper.setHGap(0); 控制子元素之间的水平间距return new BaseDelegeteAdapter(gridLayoutHelper, R.layout.vlayout_menu, 10) {@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, final int position) {holder.setText(R.id.tv_menu_title_home, ITEM_NAMES[position] + "");holder.setImageResource(R.id.iv_menu_home, IMG_URLS[position]);holder.getView(R.id.ll_menu_home).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(getApplicationContext(), ITEM_NAMES[position], Toast.LENGTH_SHORT).show();}});}};}private BaseDelegeteAdapter getNewsAdapter() {return new BaseDelegeteAdapter(new LinearLayoutHelper(), R.layout.vlayout_news, 1) {@Overridepublic void onBindViewHolder(@NonNull BaseViewHolder holder, int i) {MarqueeView marqueeView1 = holder.getView(R.id.marqueeView1);MarqueeView marqueeView2 = holder.getView(R.id.marqueeView2);List<String> info1 = new ArrayList<>();info1.add("天猫超市最近发大活动啦,快来抢");info1.add("没有最便宜,只有更便宜!");List<String> info2 = new ArrayList<>();info2.add("这个是用来搞笑的,不要在意这写小细节!");info2.add("啦啦啦啦,我就是来搞笑的!");marqueeView1.startWithList(info1);marqueeView2.startWithList(info2);// 在代码里设置自己的动画marqueeView1.startWithList(info1, R.anim.anim_bottom_in, R.anim.anim_top_out);marqueeView2.startWithList(info2, R.anim.anim_bottom_in, R.anim.anim_top_out);marqueeView1.setOnItemClickListener(new MarqueeView.OnItemClickListener() {@Overridepublic void onItemClick(int position, TextView textView) {Toast.makeText(getApplicationContext(), textView.getText().toString(), Toast.LENGTH_SHORT).show();}});marqueeView2.setOnItemClickListener(new MarqueeView.OnItemClickListener() {@Overridepublic void onItemClick(int position, TextView textView) {Toast.makeText(getApplicationContext(), textView.getText().toString(), Toast.LENGTH_SHORT).show();}});}};}
}

Demo地址:https://github.com/987570437/VLayoutDemo

使用Vlayout打造淘宝首页相关推荐

  1. 词云中去重复的词_手把手教你怎么挖掘蓝海词,打造淘宝爆款标题

    要制作一个好的标题,首先,我们需要挑选出相对蓝海并且与产品相关性高的关键词. 选词的途径主要有几个: 1. 淘宝首页-你是不是想找和下拉列表 2. 直通车-工具-流量解析-推广词表下载 3. 生意参谋 ...

  2. 互联网晚报 | 9月19日 星期日 | OPPO否认裁员20%;淘宝首页将为直播新增一级入口;蔚来打通京津冀都市圈高速换电网络...

    今日看点 ✦ 海航重整后老股东团队股权清零,将拆分为四个板块独立运营 ✦ OPPO回应裁员20%传闻:严重不实信息,各方面工作有序开展 ✦ 淘宝首页将为直播新增一级入口,并推出内容商业化平台" ...

  3. 淘宝首页焦点图设计分析

    淘宝首页每天都有那么多的焦点图,在同等展现量的情况下,究竟哪些焦点图可以获取更多的点击量呢. 于是我就找了几张曾现出现过的焦点图做了一个小调研,调研人群仅涉及到我QQ上的一些朋友.并且调研人数基数也很 ...

  4. 两分钟打造淘宝抢单机器人

    1 痛点 各大电商在一些特定的日子都会开启促销活动,如618.双十一等,有时还得盯着时间抢限量发售的商品,但你的成功率高吗?是否经常会遇到App一直加载,刷新后发现商品被一扫而光了?事实是,很多和你竞 ...

  5. 还原淘宝首页最顶部的导航栏(含下拉菜单,图标等)

    还原了淘宝首页最顶部的导航栏,包括了各个导航的下拉列表等(位置对齐稍微有些偏差,毕竟没有原版设计图),用到了jquery,js,CSS3等知识.没有花时间去做录屏GIF,就几张效果图看下:如下 原始导 ...

  6. HTML+CSS零基础学习笔记(五)— 模拟淘宝首页(静态)

    内容概览 模拟淘宝首页(静态) 一.项目重难点 二.效果图及源码 模拟淘宝首页(静态) 一.项目重难点 样式重置:在实际开发过程中,我们往往会新建一个单独的CSS文件(reset.css),用于对应H ...

  7. 页面布局(1):淘宝首页

    大家好,我是梅巴哥er. 入职前端后,我相信有很多小伙伴都是从写简单页面或者简单的功能开始入手的.比如活动页面,活动详情页,活动某项交互等. 为了快速适应开发需求,在较短时间内完成手头工作,以便挤出更 ...

  8. 淘宝首页链接跳转,非taobao.com域名下的链接处理

    淘宝首页需要实现这样一个功能,对于页面上非taobao.com域名下的链接,在用户点击时,需要在链接处弹出提示框,提示用户此链接非淘宝域名下的链接,并给与用户选择是否继续访问.如果用户确认继续访问,则 ...

  9. 2016淘宝首页改版 细说淘宝首页设计变化史

    近日,从微博上看到有网友说淘宝首页改版,现在淘宝正在一步步接入新版本,知情人士从3月22日就已经得到了淘宝官方人员的消息:新版资源位3月24日开始会接入部分流量,到时新旧版资源位会共存一段时间,直到旧 ...

最新文章

  1. 【leetcode238】Product of Array Except Self
  2. 地铁里运用计算机视觉的场景,人工智能技术在地铁运营场景应用研究报告(26页)...
  3. window.showModalDialog弹出模态窗口
  4. 测试思想-测试设计 测试用例设计之正交法
  5. 转载 | Systemd的使用简介
  6. 选择排序算法-C程序设计
  7. weblogic时间问题
  8. 【转】如何通过事物代码查找对应BAPI
  9. 如何删除服务中不存在在服务
  10. 界面扩大缩小操作按钮_少儿编程|04.Scratch编程基本操作
  11. 测试手机功耗软件,借助软件测试手机基本峰值功耗
  12. OpenGL 视椎体剔除算法
  13. 组合排列中重复数问题
  14. 时间换算--C语言结构练习
  15. 来 不 及 认 真 的 年 轻
  16. 计算机怎么打开隐藏的项目,最全面win10怎么打开隐藏文件夹
  17. 世纪标准-海岸试验数据管理系统(海岸TDM)
  18. 读一部会让你惊叹的作品——《最后一个莫西干人》
  19. AI入门基础工具(一)
  20. 微信小程序 使用 uCharts 图表

热门文章

  1. ORBSLAM2编译依赖(实现视觉SLAM)
  2. PHA关闭测试网、预备网即将正式上线!
  3. c语言优先队列对数组的排序,优先队列+sort+栈+队列讲解
  4. GK2302开卡工具,GK2301LT量产软件,国科微GK2301LT怎么开卡方法,GK2302量产开卡工具教程
  5. JAVA 分支结构 swit结构 for循环
  6. Ins资源批量爬取(二)
  7. Linux 用户账户信息 passwd结构体
  8. mat opencv 修改roi_OpenCV Android:在新Mat中定义并保存ROI(OpenCV Android: Define and save ROI in new Mat)...
  9. 暑期学习日记30:js数学
  10. 第7节 利用win7漏洞绕过系统登录密码