【Android】快速实现仿美团选择城市界面,薪资翻倍

本文介绍了如何在Android中快速实现仿美团的城市选择界面,包括处理头部复杂HeaderView、实现分组悬停和索引导航,以及核心代码实现。文章通过重构代码展示了如何规划面试学习方向,强调了系统化学习的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上文提到,重构后,SuspensionDecoration数据源依赖的接口是ISuspensionInterface

如下:

public interface ISuspensionInterface {

//是否需要显示悬停title

boolean isShowSuspension();

//悬停的title

String getSuspensionTag();

}

BaseIndexBean里实现,默认显示悬停,分组title和IndexBar的Tag是一样的。

public abstract class BaseIndexBean implements ISuspensionInterface {

private String baseIndexTag;//所属的分类(城市的汉语拼音首字母)

@Override

public String getSuspensionTag() {

return baseIndexTag;

}

@Override

public boolean isShowSuspension() {

return true;

}

}

BaseIndexPinyinBean类,现在如下:

public abstract class BaseIndexPinyinBean extends BaseIndexBean {

private String baseIndexPinyin;//城市的拼音

//是否需要被转化成拼音, 类似微信头部那种就不需要 美团的也不需要

//微信的头部 不需要显示索引

//美团的头部 索引自定义

//默认应该是需要的

public boolean isNeedToPinyin() {

return true;

}

//需要转化成拼音的目标字段

public abstract String getTarget();

}

所以我们需要实现微信那种效果,只需要重写isShowSuspension()isNeedToPinyin()这两个方法,并setBaseIndexTag()直接设置tag即可。

仿美团选择城市

=======

这个页面还是挺麻烦的,所以步骤也最多。建议结合代码阅读Demo及库地址

分析美团选择城市列表:

* 主体部分仍旧是一个普通的 分组悬停&索引导航 的列表(美团没有悬停功能)。

* 头部是由若干复杂HeaderView组成。

* 从右侧索引栏可以看出,定位、最近、热门这三个Item对应了列表三个HeaderView。

* 最顶部的HeaderView是不需要分组,也不需要索引的。

那么逐一实现:

主体部分

很简单,根据前文最后的封装( 第二篇戳我),如果只有主体部分,我们需要让主体部分的JavaBean继承自BaseIndexPinyinBean,然后正常构建数据,最终设置给IndexBar和SuspensionDecoration即可。

public class MeiTuanBean extends BaseIndexPinyinBean {

private String city;//城市名字

@Override

public String getTarget() {

return city;

}

}

头部若干HeaderViews

这里不管是通过HeaderView添加进来头部布局,还是通过itemViewType自己去实现,核心都是通过itemViewType去做的。

也就是说头部的HeaderView也是RecyclerView的Item。

既然是Item一定对应着相应的JavaBean。

我们需要针对这些JavaBean让其分别继承BaseIndexPinyinBean

具体怎么实现头部布局不是本文重点,不再赘述,Demo里有代码可细看Demo及库地址

定、近、热三个HeaderView的处理

定、近、热三个HeaderView有如下特点:

* 右侧导航索引的title 为自定义,不是拼音首字母则也不需要排序。

* 悬停分组的title 和 右侧导航索引的title 不一样,则悬停分组的title也需要自定义

做法:

不过既然是RecyclerView里的Item,又有 悬停分组、索引导航 特性。那么就要继承BaseIndexPinyinBean

* 不需要转化成拼音且不排序,则重写isNeedToPinyin()返回false,并调用setBaseIndexTag(indexBarTag)给右侧索引赋值。

* 需要自定义悬停分组的title,则重写getSuspensionTag()返回title。

public class MeituanHeaderBean extends BaseIndexPinyinBean {

private List cityList;

//悬停ItemDecoration显示的Tag

private String suspensionTag;

public MeituanHeaderBean(List cityList, String suspensionTag, String indexBarTag) {

this.cityList = cityList;

this.suspensionTag = suspensionTag;

this.setBaseIndexTag(indexBarTag);

}

@Override

public String getTarget() {

return null;

}

@Override

public boolean isNeedToPinyin() {

return false;

}

@Override

public String getSuspensionTag() {

return suspensionTag;

}

}

private List<MeituanHeaderBean> mHeaderDatas; 保存定、近、热头部数据源,最终需要将其设置给IndexBarSuspensionDecoration

mHeaderDatas = new ArrayList<>();

List locationCity = new ArrayList<>();

locationCity.add(“定位中”);

mHeaderDatas.add(new MeituanHeaderBean(locationCity, “定位城市”, “定”));

List recentCitys = new ArrayList<>();

mHeaderDatas.add(new MeituanHeaderBean(recentCitys, “最近访问城市”, “近”));

List hotCitys = new ArrayList<>();

mHeaderDatas.add(new MeituanHeaderBean(hotCitys, “热门城市”, “热”));

最顶部的HeaderView

最顶部的HeaderView,由于不需要右侧索引,也没有悬停分组。它只是一个普通的HeaderView即可。

对于这种需求的HeaderView,只需要将它们的数量传给IndexBarSuspensionDecoration 即可。

在内部我已经做了处理,保证联动坐标和数据源下标的正确。

mDecoration.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size()));

mIndexBar.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size());

这里用headerView一共的count=4,减去上步中mHeaderDatas的size =3,得出不需要右侧索引,也没有悬停分组 头部的数量。

将主体数据集和头部数据集合并

我们前几步中,设计到了三部分数据集,

一部分是主体数据集,

//主体部分数据源(城市数据)

private List mBodyDatas;

第二部分是需要特性的头部数据集

//头部数据源

private List mHeaderDatas;

第三部分是不需要特性的数据集,这里忽略。我们只用到它的count。

我们需要将第一和第二部分融合,并且设置给IndexBarSuspensionDecoration

则我们利用它们共同的基类,BaseIndexPinyinBean来存储。

核心代码如下:

//设置给InexBar、ItemDecoration的完整数据集

private List mSourceDatas;

mSourceDatas.addAll(mHeaderDatas);

mSourceDatas.addAll(mBodyDatas);

设置给IndexBar

mIndexBar.setmPressedShowTextView(mTvSideBarHint)//设置HintTextView

.setNeedRealIndex(true)//设置需要真实的索引

.setmLayoutManager(mManager)//设置RecyclerView的LayoutManager

.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size());

.setmSourceDatas(mSourceDatas)//设置数据

设置给SuspensionDecoration

mRv.addItemDecoration(new SuspensionDecoration(this, mSourceDatas)

.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size()));

效果图如文首。

核心代码

这里再提一点,我已经将排序功能抽离至IndexBarIIndexBarDataHelper类型变量中去做,

mIndexBar.setmSourceDatas(mSourceDatas)时会自动排序。

也可以手动调用mIndexBar.getDataHelper().sortSourceDatas(mBodyDatas);排序。

像本节的案例,可以选择先排序bodyDatas,然后再合并至sourceDatas,最终设置给IndexBarSuspensionDecoration

如:

//先排序

mIndexBar.getDataHelper().sortSourceDatas(mBodyDatas);

mSourceDatas.addAll(mBodyDatas);

mIndexBar.setmSourceDatas(mSourceDatas)//设置数据

.invalidate();

mDecoration.setmDatas(mSourceDatas);

涉及到的重构代码:

除了上节提到的那些数据结构的重构,

我还将以前在IndexBar里完成的:

  • 1 将汉语转成拼音

  • 2 填充indexTag

  • 3 排序源数据源

  • 4 根据排序后的源数据源->indexBar的数据源

抽成一个接口表示,与IndexBar分离。

/**

  • 介绍:IndexBar 的 数据相关帮助类

  • 1 将汉语转成拼音

  • 2 填充indexTag

  • 3 排序源数据源

  • 4 根据排序后的源数据源->indexBar的数据源

  • 作者:zhangxutong

  • 邮箱:mcxtzhang@163.com

  • 主页:http://blog.youkuaiyun.com/zxt0601

  • 时间: 2016/11/28.

*/

public interface IIndexBarDataHelper {

//汉语-》拼音

IIndexBarDataHelper convert(List<? extends BaseIndexPinyinBean> data);

//拼音->tag

IIndexBarDataHelper fillInexTag(List<? extends BaseIndexPinyinBean> data);

//对源数据进行排序(RecyclerView)

IIndexBarDataHelper sortSourceDatas(List<? extends BaseIndexPinyinBean> datas);

//对IndexBar的数据源进行排序(右侧栏),在 sortSourceDatas 方法后调用

IIndexBarDataHelper getSortedIndexDatas(List<? extends BaseIndexPinyinBean> sourceDatas, List datas);

}

IndexBar内部持有这个接口的变量,调用其中方法完成需求:

public IndexBar setmSourceDatas(List<? extends BaseIndexPinyinBean> mSourceDatas) {

this.mSourceDatas = mSourceDatas;

initSourceDatas();//对数据源进行初始化

return this;

}

/**

  • 初始化原始数据源,并取出索引数据源

  • @return

*/

private void initSourceDatas() {

//add by zhangxutong 2016 09 08 :解决源数据为空 或者size为0的情况,

if (null == mSourceDatas || mSourceDatas.isEmpty()) {

return;

}

if (!isSourceDatasAlreadySorted) {

//排序sourceDatas

mDataHelper.sortSourceDatas(mSourceDatas);

} else {

//汉语->拼音

mDataHelper.convert(mSourceDatas);

//拼音->tag

mDataHelper.fillInexTag(mSourceDatas);

}

if (isNeedRealIndex) {

mDataHelper.getSortedIndexDatas(mSourceDatas, mIndexDatas);

computeGapHeight();

}

}

我在sortSourceDatas()实现里,已经调用了convert(datas);fillInexTag(datas);

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

image

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

image

点击:《Android架构视频+BAT面试专题PDF+学习笔记》即可免费获取~

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

[外链图片转存中…(img-om9xfHK2-1646238628530)]

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

[外链图片转存中…(img-cux7p74G-1646238628531)]

点击:《Android架构视频+BAT面试专题PDF+学习笔记》即可免费获取~

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值