A ListView that allows the head to hover is often used in a project, such as a friend list for QQ or a regional selection.
Not much to say, see: (Lazy on the GIF picture)
I've done some analysis here, drawing on the core code of others.
The main use of Pinnedsectionlistview is to replace the ListView.
The pinnedsectionlistview here is someone else's. We mainly look at how to use this pinnedsectionlistview and how to fit the data into it.
At the end of the blog post I will upload a demo with Pinnedsectionlistview and complete items. You can follow this blog to see how the data fit in.
First look at the project structure chart:
Which: Pinnedsectionlistview is the same as the others
The other is the class that fits the ListView and the data
1,activity
The activity is simple.
Public class indexactivity extends appcompatactivity { PrivatePinnedsectionlistview pinned_section_list;PrivateIndexadapter Indexadapter;PrivateList<citybean> data;@Override Public void onCreate(@Nullable Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setcontentview (R.layout.activity_main);//Instantiate a control with a hover headerPinned_section_list = (Pinnedsectionlistview) Findviewbyid (r.id.pinned_section_list);//Analog datadata =NewTestData (). InitData ();//Initialize adapterIndexadapter =NewIndexadapter ( This, data);//Add AdapterPinned_section_list.setadapter (Indexadapter); }}
2,xml layout
<?xml version= "1.0" encoding= "Utf-8"?><relativelayout xmlns:android="Http://schemas.android.com/apk/res/android" android:layout_width="Match_parent"android:layout_height="Match_parent" > <com.android.list.PinnedSectionListViewandroid:id="@+id/pinned_section_list" android:layout_width="Match_parent"android:layout_height="Match_parent" Android:divider="@null"android:footerdividersenabled="false" android:headerdividersenabled="false" /> </relativelayout>
3, City entity class
publicclass CityBean { privateint cityId;//城市id private String cityName;//城市名 privateint superiorId;//上级城市id private List<CityBean> subordinateList;//下级城市集合 //忽略get/set方法 }
4, test data, simulate city data
Public classTestData {PrivateList<citybean> data; PublicList<citybean>InitData() {data =NewArraylist<> (); for(intj =1; J < One; J + +) {list<citybean> beijinglist =NewArraylist<> (); for(inti =1; I < One; i++) {Citybean Citybean =NewCitybean (); Citybean.setcityid (i +Ten); Citybean.setcityname ("Beijing"+ i +"Area"); Beijinglist.add (Citybean); } Citybean Citybean =NewCitybean (); Citybean.setcityid (1); Citybean.setcityname ("Beijing", M); Citybean.setsubordinatelist (beijinglist); Data.add (Citybean); List<citybean> shanghailist =NewArraylist<> (); for(inti =1; I < One; i++) {Citybean CityBean1 =NewCitybean (); Citybean1.setcityid (i + -); Citybean1.setcityname ("Shanghai"+ i +"Area"); Shanghailist.add (CITYBEAN1); } Citybean CityBean1 =NewCitybean (); Citybean1.setcityid (2); Citybean1.setcityname ("Shanghai"+ j); Citybean1.setsubordinatelist (shanghailist); Data.add (CITYBEAN1); List<citybean> shenzhenlist =NewArraylist<> (); for(inti =1; I < One; i++) {Citybean cityBean2 =NewCitybean (); Citybean2.setcityid (i + -); Citybean2.setcityname ("Shenzhen"+ i +"Area"); Shenzhenlist.add (CITYBEAN2); } Citybean cityBean2 =NewCitybean (); Citybean2.setcityid (3); Citybean2.setcityname ("Shenzhen", M); Citybean2.setsubordinatelist (shenzhenlist); Data.add (CITYBEAN2); }returnData }}
5,item class, the object that is actually displayed in the ListView
Public class Item { Public Static Final intITEM =0;//Determine if it is a normal item Public Static Final intSection =1;//Determine if the item you want to hover on is pinned Public Final intType//External incoming type, item or section Public FinalCitybean Citybean;//external incoming data, here we write it as a city entity class, can be arbitrarily replaced Public intSectionposition;//head mark, usually with the ID tag of the parent data Public intListposition;//Set tag, usually tagged with its own ID Public Item(intType, Citybean Citybean) { This. type = type; This. Citybean = Citybean; }//Get the data saved PublicCitybeanGetcitybean() {returnCitybean; }}
The item class is used to hold data that is passed in externally and to set whether the type of the data belongs to the hover header or plain item.
6, the most important, adapter
The adapter for the hover ListView must implement the interface in Pinnedsectionlistview: Pinnedsectionlistadapter and Android Native interface: Sectionindexer
Public class indexadapter extends baseadapter implements Pinnedsectionlistview. pinnedsectionlistadapter, sectionindexer { //In order to distinguish the background color of the head, can also be replaced by other means. Example: Layout style Private Static Final int[] COLORS =New int[]{r.color.green_light, R.color.orange_light, R.color.blue_light, r.color.red_light};PrivateList<citybean> data;//raw data sent in externally Privatelist<item> items;//This is the list that is actually displayed PrivateContext context;PrivateItem[] sections;//Header tag Array Public Indexadapter(context context, list<citybean> data) { This. data = data; This. Context = Context; Initsection (); }//Initialize display data Private void initsection() {items =NewArraylist<> (); Sections =NewItem[data.size ()];//Data Preparation for(inti =0; I < data.size (); i++) {//Add header information to pass in header tags and dataItem section =NewItem (Item.section, Data.get (i)); Section.sectionposition = Data.get (i). Getcityid ();//The parent City ID is passed in as the header ID, because the parent class ID does not have a superior city, so it passes its own IDSection.listposition = Data.get (i). Getcityid ();//pass in its own ID, passing the current city ID as a normal ID The tag of the city ID in the//header tag group corresponds to the item instance in the citySections[section.sectionposition] = section; Items.Add (section);//Subordinate cities of the current city for(intj =0; J < Data.get (i). Getsubordinatelist (). Size (); J + +) {//subordinate city for normal ITEM, so incoming Item.itemItem item =NewItem (Item.item, Data.get (i). Getsubordinatelist (). Get (j)); Item.sectionposition = Data.get (i). Getcityid ();//Pass in the parent city ID as the header ID to prove which city belongs to the parent city under the ordinary IDItem.listposition = Data.get (i). Getsubordinatelist (). Get (J). Getcityid ();//pass in its own ID, passing the current city ID as a normal IDItems.Add (item); } } }/************************* * The following is the Pinnedsectionlistview override method *************************************************/< /c4> //Current view is a fixed item @Override Public Boolean isitemviewtypepinned(intViewType) {returnViewType = = Item.section; }/************************* * The following is the adapter override method *************************************************/ number of incoming view types, indicating several view types //pinnedsectionlistview If adapter getviewtypecount<2 is found to throw an exception @Override Public int Getviewtypecount() {return 2; }//Returns the type of each view @Override Public int Getitemviewtype(intPosition) {returnGetItem (position). type; }@Override Public int GetCount() {returnItems.size (); }@Override PublicItemGetItem(intPosition) {returnItems.get (position); }@Override Public Long Getitemid(intPosition) {returnPosition }@Override PublicViewGetView(intPosition, view view, ViewGroup parent) {View V; Viewholder VH; Item item = items.get (position);//Get the current row's data from the collection if(View = =NULL) {//indicates that the current line is not reusable //Load line layout file to produce a specific linev = view.inflate (context, R.layout.item,NULL);//Create an object that stores a row of controlsVH =NewViewholder ();//Save all the controls in the row to VHVh.tvname = (TextView) V.findviewbyid (R.id.text_text); V.settag (VH);//Store VH in the row's tag}Else{v = view;//Remove the tag--in a hidden row take out the VH control cache object hidden in this rowVH = (Viewholder) view.gettag (); }//Change the value of a control from a Viewholder cached control //This is mainly to avoid the waste of resources caused by multiple forced conversion of target objectsVh.tvName.setText (Item.getcitybean (). Getcityname ());if(Item.type = = item.section) {V.setbackgroundcolor (Parent.getresources (). GetColor (colors[item.sectionposition% colors.length])); }returnV }//Store controls in one row (caching)---Avoid multiple strong turns on each row of controlsClass Viewholder {TextView tvname; }/************************ * The following is an overriding method of the Sectionindexer interface ******************************************/ //Returns an array of objects representing the part of the list used to display the header //The item[returned here] is the part of the head that is loaded @Override PublicItem[]getsections() {returnSections }A partial object within the array of the given index part, returning the starting position in the adapter section. @Override Public int getpositionforsection(intSectionindex) {//Avoid throwing Exceptions if(Sectionindex >= sections.length) {Sectionindex = sections.length-1; }//Returns the header ID of the current header collection returnSections[sectionindex].listposition; }//Given a position within an adapter, returns a portion of the object within the corresponding index part array. @Override Public int getsectionforposition(intPosition) {if(Position >= GetCount ()) {position = GetCount ()-1; }//Returns the header ID saved in the current item returnGetItem (position). sectionposition; }}
This is the code for the whole project, and it's interesting to see how Pinnedsectionlistview is implemented. I saw part of it because the time relationship did not go on.
Demo download
Android ui--Group + hover ListView