The previous article on the ListView Grouping and the letter index navigation implementation idea has done the analysis, and follows the thought step by step realization, finally already better realizes the entire function. But careful study will find that its implementation is not good enough, the main problem:
1. For a widely used layout, the above implementations are not common enough, especially if you need to add some extra fields to the Bo, the fields themselves are meaningless.
2. The code is all mixed up in the activity.
Do some code refactoring for the above two points. First, we optimize it as a generic activity. It's easy to make a generic view, and then extract and refactor the code.
Ideas and ideas
One of the main problems with the previous code is "pollution" of the original Bo, and the main reason for the pollution is the need to use these additional fields for data processing and the generation of list group labels when used.
The original code is as follows:
public class Testbo { /** * Primary field */ private String bostr = null; /** * bo Pinyin cache */ private String bopinyin = null; /** * bo tag tag */ private String botagflag = null; Public Testbo () { super (); } Public Testbo (String str) { super (); This.bostr = str; } Public String Getbostr () { return bostr; } public void Setbostr (String bostr) { this.bostr = bostr; } Public String Getsortstrpinyin () { return bopinyin; } public void Setsortstrpinyin (String pinyin) { this.bopinyin = pinyin; } public void Settag (String tag) { This.botagflag = tag; } Public String Gettag () { return botagflag; }}
In fact, the above Bo really useful has the main field, the others are additional fields, in fact, the generated list as long as the Bo provided by which field to group on the line.
Naturally we think of the interface, as long as the corresponding interface is implemented, the interface method returns the need to "group sorting values."
Data processing can be changed accordingly.
Refactoring bo-Interface
The following interfaces are extracted first:
Public interface Bosort { /** * @date 2014-9-3 * @Description: Gets the indexed string * @param * @return String * /public string getsortstr (); /** * @date 2014-9-3 * @Description: Gets the index string pinyin, this best can have the cache * @param * @return string * * Public String Getsortstrpinyin (); /** * @date 2014-9-3 * @Description: * @param * @return void */public void Setsortstrpinyin (String pinyin); /** * @date 2014-9-3 * @Description: Set tag, need cache * @param * @return void */public void Settag (String tag); /** * @date 2014-9-3 * @Description: Gets the label, if NULL, the description is not a label * @param * @return String * * Public String Gettag ();}
The corresponding Bo implements the above interface. But we can provide a default implementation, which is also an abstract class, as long as Bo inherits this default implementation and implements the method for implementation
PublicString Getsortstr ();
/** * @date 2014-9-3 * @Description: Just implement GETSORTSTR other do not modify */public abstract class Defaultbosortimp Implements bosort{ /** * bo Pinyin cache */ private String bopinyin = null; /** * bo tag tag */ private String botagflag = null; /** * Must have this constructor * /Public defaultbosortimp () { super (); } @Override public String Getsortstrpinyin () { return bopinyin; } @Override public void Setsortstrpinyin (String pinyin) { this.bopinyin = pinyin; } @Override public void Settag (String tag) { This.botagflag = tag; } @Override public String Gettag () { return botagflag; }}
Data processing
The overall implementation process is similar to the previous, with a slight change in data processing. We take the data processing separately as a class, visible processing process, the generation of packet labels when the use of reflection, and this data processing only depends on the interface, rather than the specific Bo, reducing the coupling.
public class Rulerutil {/** * list adaptation?? */public static final string[] Indexstr = {"#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L "," M "," N "," O "," P "," Q "," R "," S "," T "," U "," V "," W "," X "," Y "," Z "}; public static final char[] letters = {' A ', ' B ', ' C ', ' D ', ' E ', ' F ', ' G ', ' H ', ' I ', ' J ', ' K ', ' L ', ' M ', ' N ', ' O ', ' P ', ' Q ', ' R ', ' S ', ' T ', ' U ', ' V ', ' W ', ' X ', ' Y ', ' Z '}; /** * @throws illegalaccessexception * @throws instantiationexception * @return return processed data * @Description: Processing number According to, sort, add label */public static arraylist<bosort> gensorteddataandtaglocation (list<? extends bosort> MyData , hashmap<string, integer> taglocation) throws Instantiationexception, illegalaccessexception {Ar raylist<bosort> res = new arraylist<bosort> (); Res.addall (MyData); First sort Collections.sort (res, new comparator<bosort> () { @Override public int Compare (Bosort lhs, bosort rhs) {char Firchar = Checkandgetpinyin (LHS); Char Secchar = Checkandgetpinyin (RHS); if (Firchar < Secchar) {return-1; } else if (Firchar > Secchar) {return 1; } else return 0; } }); int size = Res.size (); int i = 0; Char Nowtag = ' + '; for (i = 0; i < size; i++) {Bosort temp = res.get (i); Char Temptag = checkandgetpinyin (temp); if (Arrays.binarysearch (Letters, Temptag) < 0) {Temptag = ' # '; } if (Nowtag! = Temptag) {//reflection generate label class<? extends bosort> Boclass = TEMP.GETCL (); Bosort Tagbo = Boclass.newinstance (); Tagbo.settag (temptag+ ""); Res.add (i, Tagbo); Taglocation.put (Temptag + "", I); i++; size++; Nowtag = Temptag; }} taglocation.put ("#", 0); return res; } private static char Checkandgetpinyin (Bosort bo) {String pinyinstr = Bo.getsortstrpinyin (); if (pinyinstr==null) {Bo.setsortstrpinyin (Hanzitopinyin.getpinyin (Bo.getsortstr ()). toUpperCase ()); Pinyinstr = Bo.getsortstrpinyin (); } if (Pinyinstr!=null&&pinyinstr.length () >=1) {return Pinyinstr.charat (0); } return ' to '; }}
Adaptor implementation
The implementation of Adptor is the same as before, but only adaptor is also dependent on the interface and does not depend on the specific Bo.
Refactoring of activity
Constructs a generic abstract activity. When a group navigation is required, it is only necessary to inherit and implement the method of returning the data.
First, the right-hand index is drawn out and made into a view.
1. Rulerwidget
A separate view that can be used directly in the XML layout.
/** * @Description: Right ruler navigation, call Setonrulertouch method to set callback interface */public class Rulerwidget extends linearlayout{private static final int index_length = RulerUtil.indexStr.length; Public Rulerwidget (Context context) {super (context); Init (); } public Rulerwidget (context context, AttributeSet Attrs) {Super (context, attrs); Init (); } public Rulerwidget (context context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle); Init (); } private void Init () {int color = getresources (). GetColor (R.color.g_ruler_letter_color); Linearlayout.layoutparams params = new Linearlayout.layoutparams (layoutparams.wrap_content, LayoutParams.WRAP_ CONTENT); params.gravity = Gravity.center_horizontal; This.bringtofront (); Params.weight = 1; for (int i = 0; i < RulerUtil.indexStr.length; i++) {final TextView TV = new TextView (GetContext ()); Tv.setlayoutparams (params); Tv.settextcolor (color); Tv.setgravity (Gravity.center); Tv.settext (Rulerutil.indexstr[i]); This.addview (TV); } this.setontouchlistener (New Ontouchlistener () {@Override public boolean onTouch (View V, Moti OnEvent event) {int height = v.getheight (); float pos = event.gety (); int sectionposition = (int) ((pos/height)/(1f/index_length)); if (Sectionposition < 0) {sectionposition = 0; } else if (Sectionposition > index_length-1) {sectionposition = index_length-1; } switch (Event.getaction ()) {Case MotionEvent.ACTION_DOWN:if (onrulertouch! =null) {Onrulertouch.ondown (sectionposition); } RulerWidget.this.setBackgroundResource (r.color.g_ruler_selected); Break CasE MotionEvent.ACTION_MOVE:if (onrulertouch!=null) {Onrulertouch.onmove (sectionposit ION); } break; Default:if (onrulertouch!=null) {onrulertouch.onothers (); } RulerWidget.this.setBackgroundResource (R.color.g_blank); } return true; } }); }/** * CALLBACK * */private Onrulertouch Onrulertouch; public void Setonrulertouch (Onrulertouch onrulertouch) {this.onrulertouch = Onrulertouch; }}/** * @date 2014-9-3 * @Description: Ruler Touch Callback */public interface onrulertouch{public void Ondown (int position); public void OnMove (int position); public void Onup (); public void Onothers ();}
2. Activity
An abstract activity. The layout is similar to the previous. Not posted.
/** * @date 2014-9-3 * @Description: Need to implement this method of obtaining data * public abstract list<? Extends bosort> getdatalist (); */public abstract class Ruleractivity extends activity{protected TextView Nodataview; protected TextView Rulertag; protected Progressbarwithtext progress; Protected ListView ListView; protected Rulerwidget ruler; Private Ruleradapter Ruleradapter; Private list<? Extends bosort> originallist; Private list<bosort> dealedlist; Private hashmap<string, integer> taglocation = new hashmap<string, integer> (); /** * */@Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (Savedinstanc EState); Setcontentview (R.layout.g_ruler); Findview (); Initview (); InitData (); } private void Findview () {Nodataview = (TextView) Findviewbyid (r.id.g_base_list_nodata); Rulertag = (TextView) Findviewbyid (R.id.g_ruler_tag); ProgRess = (progressbarwithtext) Findviewbyid (R.id.g_base_progressbar_withtext); ListView = (ListView) Findviewbyid (R.id.g_base_list); Ruler = (rulerwidget) Findviewbyid (R.id.g_ruler); } private void Initview () {progress.setvisibility (view.visible); Rulertag.setvisibility (View.gone); Nodataview.setvisibility (View.gone); Listview.setvisibility (View.gone); Ruler.setvisibility (View.gone); } private void InitData () {new Getdataasytask (). Execute (); }/** * @date 2014-9-4 * @Description: Need to implement this method of obtaining data * @param * @return list< Extends bosort> * * public abstract list<? Extends bosort> getdatalist (); /** * @date 2014-9-3 * @Description: * @param * @return void */private void Handlesuccessdata () { Listview.setvisibility (view.visible); Ruler.setvisibility (view.visible); Ruleradapter = new Ruleradapter (dealedlist, this); Ruler.setonrulertoUch (New Onrulertouch () {@Override public void Onup () {} @Override Publ IC void Onothers () {rulertag.setvisibility (view.gone); } @Override public void onMove (int position) {Rulertag.settext (Rulerutil.indexstr[positi On]); Listview.setselection (getPosition (position)); } @Override public void Ondown (int position) {rulertag.setvisibility (view.visible); Rulertag.settext (Rulerutil.indexstr[position]); Listview.setselection (getPosition (position)); } }); Listview.setadapter (Ruleradapter); Ruleradapter.notifydatasetchanged (); }/** * @Description: Gets the position of the list to scroll to when navigating the letter with the touch. If the touch of the letter, in the label taglocation mapping, does not exist, then look forward. */Private Integer getPosition (final int j) {Integer pos = null; int i = j; while (pos = = null && i <= rulerutil.indexstr.length-1) {pos = Taglocation.get (Rulerutil.indexstr[i]); i++; } if (pos = = null) {pos = Dealedlist.size ()-1; } return POS; } class Getdataasytask extends Asynctask<void, Void, void> {@Override protected V OID OnPreExecute () {super.onpreexecute (); Progress.setvisibility (view.visible); } @Override protected void Doinbackground (void ... params) {originallist = Getdatalist (); try {dealedlist = rulerutil.gensorteddataandtaglocation (originallist, taglocation); } catch (Exception e) {e.printstacktrace (); if (dealedlist!=null) {dealedlist.clear (); Dealedlist = null; } if (Originallist!=null) {originallist.clear (); Originallist = null; } if (tAglocation!=null) {taglocation.clear (); Taglocation = null; }} return null; } @Override protected void onpostexecute (void result) {progress.setvisibility (view.gone); Super.onpostexecute (result); if (dealedlist==null) {nodataview.setvisibility (view.visible); Return } handlesuccessdata (); } } }
This refactoring is complete.
Android ListView Group and Alphabetical Index navigation (2) Refactoring-interface