An overview of the

This is the third and, unsurprisingly, final article in the series. Refactoring controls makes it possible to quickly implement index navigation, hover-grouped list interfaces on the market. In the first two articles, we started from 0 and realized the imitation wechat address book and ele. me food selection interface step by step. This article as the conclusion, compared with the previous article, mainly involves the following contents:

  • Reconstruct the hover group and rename TitleItemDecoration to SuspensionDecoration. The data source relies on ISuspensionInterface.
  • Refactoring index navigation to separate IndexBar operations on data sources, such as sorting and transliteration, and communicate with IIndexBarDataHelper.
  • More than N brothers gave me a message, add QQ asked: how to achieve Meituan select city list page,
  • Add a HeaderView without hover group

Code portal: Click star if you like. Thank you for your github.com/mcxtzhang/S…

Same old rule, first picture:.

Meituan select the city interface, refresh the Body Body data first, and then refresh the head data

Wechat Address book interface

Effect with my other library assembly (SuspensionIndexBar + SwipeMenuLayout)



Github.com/mcxtzhang/S…

This article will start with examples and explain the refactoring involved. If you are not sure, I suggest you watch it first (the first article stamp me second article stamp me), as well as download the Demo, while watching the code while reading, the effect is better.


Reprint please indicate the source: juejin.cn/post/684490… This article is from: [Zhang Xutong’s Rare earth mining] (juejin.cn/user/905653…) Code portal: Click star if you like. Thank you for your github.com/mcxtzhang/S…


Wechat address book interface writing method

From the simple usage, wechat contacts interface and ordinary group hover & index navigation list comparison:

  • Four more HeaderViews
  • These HeaderView layouts are the same as the main Item
  • These headerViews have no grouped hover titles
  • These headerViews are a set of indexed title customization

Implementation: HeaderView is not the focus of this article, so feel free to implement it. I’m using what I wrote earlier. Poke me

The layout is consistent with the body Item

Since the layout is consistent, we must be lazy to directly use the Bean of the main Item and set city to the corresponding data, such as “new friend” :

public class CityBean extends BaseIndexPinyinBean { private String city; // City nameCopy the code

No group hover

To remove the grouping hover, we need to override isShowSuspension(), returning false.

Index title User-defined

If they are a group, the index title is the same and needs to be customized. The four header beans call setBaseIndexTag(), set the custom title, and be consistent.

Mdatas.add ((CityBean) new CityBean(" new friend ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); mdatas.add ((CityBean) new CityBean(" new friend ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); Mdatas.add ((CityBean) new CityBean(" groupbean ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); mdatas.add ((CityBean) new CityBean(" groupBean ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); Mdatas.add ((CityBean) new CityBean(" tag ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); mdatas.add ((CityBean) new CityBean(" tag ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); Mdatas.add ((CityBean) new CityBean(" public ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); mdatas.add ((CityBean) new CityBean(" public ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));Copy the code

Core code:

Introduce a field isTop in CityBean

public class CityBean extends BaseIndexPinyinBean { private String city; Private Boolean isTop; // Is the top one that does not need to be converted to pinyin... @Override public String getTarget() { return city; } @Override public boolean isNeedToPinyin() { return ! isTop; } @Override public boolean isShowSuspension() { return ! isTop; }}Copy the code

Initialization:

mRv.addItemDecoration(mDecoration = new SuspensionDecoration(this, mDatas)); . / / indexbar initialization mIndexBar setmPressedShowTextView (mTvSideBarHint) / / setting HintTextView setNeedRealIndex (true) / / set need real index .setmLayoutManager(mManager); // Set RecyclerView's LayoutManagerCopy the code

Data loading:

mDatas = new ArrayList<>(); // The header of wechat can also be navigated with the right IndexBar, // But it doesn't need a title titile mdatas.add ((CityBean) new CityBean(" new friend ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); Mdatas.add ((CityBean) new CityBean(" groupbean ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); mdatas.add ((CityBean) new CityBean(" groupBean ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); Mdatas.add ((CityBean) new CityBean(" tag ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); mdatas.add ((CityBean) new CityBean(" tag ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); Mdatas.add ((CityBean) new CityBean(" public ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); mdatas.add ((CityBean) new CityBean(" public ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP)); for (int i = 0; i < data.length; i++) { CityBean cityBean = new CityBean(); cityBean.setCity(data[i]); // Set the city name mdatas.add (cityBean); }... MIndexBar. SetmSourceDatas (mDatas). / / set data invalidate (); mDecoration.setmDatas(mDatas);Copy the code

Refactoring code involved

As mentioned above, after reconstruction, the SuspensionDecoration data source relies on ISuspensionInterface, as follows:

Public interface ISuspensionInterface {// Whether to display suspension title Boolean isShowSuspension(); // Title String getSuspensionTag(); }Copy the code

Implemented in BaseIndexBean, hover is displayed by default, grouping title and IndexBar with the same Tag.

public abstract class BaseIndexBean implements ISuspensionInterface { private String baseIndexTag; @override public String suspensionTag () {return suspensionTag; } @Override public boolean isShowSuspension() { return true; }}Copy the code

The BaseIndexPinyinBean class now looks like this:

public abstract class BaseIndexPinyinBean extends BaseIndexBean { private String baseIndexPinyin; // Whether the city's pinyin needs to be converted to pinyin, Public Boolean isNeedToPinyin() {return true; public Boolean isNeedToPinyin() {return true; } public abstract String getTarget(); }Copy the code

Therefore, we need to achieve the effect of wechat, just need to rewrite isShowSuspension() and isNeedToPinyin() these two methods, and setBaseIndexTag() directly set the tag.

Choose cities in imitation of Meituan

This page is quite cumbersome, so it has the most steps. It is recommended to read the Demo and library address together with the code. Analysis of meituan select cities list:

  • The main body is still a normal list of grouped hovers and indexed navigation (there is no hover feature).
  • The header is made up of several complex HeaderViews.
  • From the index bar on the right, we can see that the location, recent and popular items correspond to the three headerViews of the list.
  • The topmost HeaderView does not need to be grouped or indexed.

Then one by one:

Main part

If we only have the body part, we need to have the body JavaBean inherit from the BaseIndexPinyinBean, then build the data normally, and eventually set it to IndexBar and SuspensionDecoration.

public class MeiTuanBean extends BaseIndexPinyinBean { private String city; // City name... @Override public String getTarget() { return city; }}Copy the code

A number of HeaderViews

So whether you’re adding the header layout through a HeaderView or you’re doing it by yourself through an itemViewType, the core is doing it through an itemViewType. That is, the header’s HeaderView is also a RecyclerView Item. Since the Item must correspond to the corresponding JavaBean. We need each of these Javabeans to inherit baseIndexPinyinBeans. Specific how to achieve the head layout is not the focus of this article, no further details, there are codes in the Demo can look at the Demo and library address.

Fixed, near, hot three HeaderView processing

Fixed, near and hot three headerViews have the following features:

  • The title of the navigation index on the right is customized, and it does not need to be sorted if the first letter is not pinyin.
  • If the title of the hover group is different from the title of the navigation index on the right, the title of the hover group also needs to be customized.

Practice: But since it is RecyclerView Item, and hover grouping, index navigation characteristics. Then you inherit the BaseIndexPinyinBean.

  • Do not need to convert to pinyin and do not sort, rewriteisNeedToPinyin()Returns false and callssetBaseIndexTag(indexBarTag)Assign a value to the right index.
  • If you need to customize the title of the hover group, overridegetSuspensionTag()Return to the title.
public class MeituanHeaderBean extends BaseIndexPinyinBean { private List cityList; // suspensionTag 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; }}Copy the code

With private List mHeaderDatas; Save the fixed, near, and hot header data sources, and eventually set them to IndexBar and SuspensionDecoration.

mHeaderDatas = new ArrayList<>(); List locationCity = new ArrayList<>(); Locationcity. add(" locating "); Mheaderdatas.add (new MeituanHeaderBean(locationCity, "locationCity "," set ")); List recentCitys = new ArrayList<>(); Mheaderdatas.add (new MeituanHeaderBean(recentCitys, "recently visited city "," near ")); List hotCitys = new ArrayList<>(); Mheaderdatas.add (new MeituanHeaderBean(hotCitys, "Hot city "," hot "));Copy the code

HeaderView at the top

HeaderView, at the top, has no hovering groups because it doesn’t need a right side index. It’s just a normal HeaderView. For the required HeaderView, just pass their number to the IndexBar and SuspensionDecoration. Internally, I have done some work to make sure the linkage coordinates and data source subscripts are correct.

mDecoration.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size()));
mIndexBar.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size());Copy the code

Count =4, subtract mHeaderDatas size =3, and get the number of group heads that do not need the right index and do not hover.

Combines the principal data set with the header data set

In the first few steps, we designed three data sets, one is the master data set,

Private List mBodyDatas;Copy the code

The second part is the header data set that requires characteristics

// Header data source private List mHeaderDatas;Copy the code

The third part is data sets that do not require features and are ignored here. We’re just going to use its count. We need to merge the first and second parts and set them up in IndexBar and SuspensionDecoration. We use their common base class, BaseIndexPinyinBean, for storage. The core code is as follows:

Private List mSourceDatas; private List mSourceDatas; mSourceDatas.addAll(mHeaderDatas); mSourceDatas.addAll(mBodyDatas);Copy the code

Set to IndexBar:

MIndexBar. SetmPressedShowTextView (mTvSideBarHint) / / setting HintTextView setNeedRealIndex (true) / / set need real index . SetmLayoutManager (mManager) / / setting RecyclerView LayoutManager setHeaderViewCount (mHeaderAdapter. GetHeaderViewCount () mHeaderDatas.size()); .setmsourceDatas (mSourceDatas)// Sets the dataCopy the code

Set to SuspensionDecoration:

        mRv.addItemDecoration(new SuspensionDecoration(this, mSourceDatas)
                .setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size()));Copy the code

The renderings are as follows.

The core code

Mention some here, I have been sorting out to IndexBar IIndexBarDataHelper type variable, in mIndexBar. SetmSourceDatas (mSourceDatas) automatically sort. You can also manually call mindexbar.getDataHelper ().sortSourceDatas(mBodyDatas); Sorting. As in the example in this section, you can choose to sort bodyDatas first, then merge to sourceDatas, and finally set to IndexBar and SuspensionDecoration. Such as:

// Sort mindexbar.getDataHelper ().sortSourceDatas(mBodyDatas); mSourceDatas.addAll(mBodyDatas); MIndexBar. SetmSourceDatas (mSourceDatas). / / set data invalidate (); mDecoration.setmDatas(mSourceDatas);Copy the code

Refactoring code involved:

In addition to the data structure refactorings mentioned in the previous section, I will also do the following in IndexBar:

  • 1 Change Chinese into Pinyin
  • 2 fill indexTag
  • 3 Sort the source data sources
  • 4 Based on sorted source data source -> Data source of indexBar

Represented as an interface, separate from IndexBar.

** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * Homepage: [email protected] * * time: http://blog.csdn.net/zxt0601 */ public interface IIndexBarDataHelper convert(List data); */ public interface IIndexBarDataHelper convert(List data); IIndexBarDataHelper fillInexTag(List data); RecyclerView IIndexBarDataHelper sortSourceDatas(List datas); IIndexBarDataHelper getSortedIndexDatas(List sourceDatas, List datAs) after sortSourceDatas; }Copy the code

IndexBar internally holds variables for this interface and calls methods to fulfill requirements:

public IndexBar setmSourceDatas(List mSourceDatas) { this.mSourceDatas = mSourceDatas; initSourceDatas(); // Initialize the data source. } /** * Initialize the original data source, * * @return */ private void initSourceDatas() {//add by Zhangxutong 2016 09 08: if (null == mSourceDatas || mSourceDatas.isEmpty()) { return; } if (! IsSourceDatasAlreadySorted) {/ / sorting sourceDatas mDataHelper. SortSourceDatas (mSourceDatas); } else {// Chinese -> pinyin mdatahelper. convert(mSourceDatas); Mdatahelper. fillInexTag(mSourceDatas); } if (isNeedRealIndex) { mDataHelper.getSortedIndexDatas(mSourceDatas, mIndexDatas); computeGapHeight(); }}Copy the code

I have called convert(datas) in the sortSourceDatas() implementation; And fillInexTag (datas);

@Override public IIndexBarDataHelper sortSourceDatas(List datas) { if (null == datas || datas.isEmpty()) { return this; } convert(datas); fillInexTag(datas); Collections.sort(datas, new Comparator() {@override public int compare(BaseIndexPinyinBean) BaseIndexPinyinBean rhs) { if (! lhs.isNeedToPinyin()) { return 0; } else if (! rhs.isNeedToPinyin()) { return 0; } else if (lhs.getBaseIndexTag().equals("#")) { return 1; } else if (rhs.getBaseIndexTag().equals("#")) { return -1; } else { return lhs.getBaseIndexPinyin().compareTo(rhs.getBaseIndexPinyin()); }}}); return this; }Copy the code

The following variables control whether sorting is required and whether index extraction is required:

// Whether to generate the index data source based on the actual data (e.g., A, B, C) private Boolean isNeedRealIndex; // Is the source data in order? private boolean isSourceDatasAlreadySorted;Copy the code

benefits

The nice thing about this is that if you don’t like my sorting, or if you want to customize the index for special characters, now “#”, you can do this by overriding the IndexBarDataHelperImpl class methods by inheritance. Or simply implement the IIndexBarDataHelper interface, which can be extended and customized for different needs without changing the IndexBar class every time.

conclusion

The pensioninterface method in ISuspensionInterface can be overwritten.

  • Whether the hover title needs to be displayed
  • Hover displays titles

Flexible override of methods in BaseIndexPinyinBean to control:

  • Whether it needs to be converted into pinyin, similar to the wechat head that does not need Meituan also does not need
  • The header of wechat does not need to display the index
  • Meituan header index custom
  • Default should be required
  • inisNeedToPinyin()Don’t forget to manually return falsesetBaseIndexTag()Set the Tag value for IndexBar.

The IIndexBarDataHelper for IndexBar provides the setHeaderViewCount(int headerViewCount) method to set the number of HeaderViews that do not require a right index or hover group.


Reprint please indicate the source: juejin.cn/post/684490… This article is from: [Zhang Xutong’s Rare earth mining] (juejin.cn/user/905653…) Code portal: Click star if you like. Thank you for your github.com/mcxtzhang/S…