The ListView of Android contacts is unique, but the source code is written to compare copy, when we want to use his time to extract from the source, it is not easy ah, and error prone, these days, I took him out, write a simple example, one is to their own memo, But to share with you, okay, let's take a look at the effect chart:
First of all, the Pinnedheaderlistview of the packaged lead department:
Copy Code code as follows:
public class Pinnedheaderlistview extends ListView {
Public interface Pinnedheaderadapter {
public static final int pinned_header_gone = 0;
public static final int pinned_header_visible = 1;
public static final int pinned_header_pushed_up = 2;
int getpinnedheaderstate (int position);
void Configurepinnedheader (View header, int position, int alpha);
}
private static final int max_alpha = 255;
Private Pinnedheaderadapter Madapter;
Private View Mheaderview;
Private Boolean mheaderviewvisible;
private int mheaderviewwidth;
private int mheaderviewheight;
Public Pinnedheaderlistview {
Super (context);
}
Public Pinnedheaderlistview (context context, AttributeSet Attrs) {
Super (context, attrs);
}
Public Pinnedheaderlistview, AttributeSet Attrs,
int Defstyle) {
Super (context, attrs, Defstyle);
}
protected void OnLayout (Boolean changed, int left, int. top, int right, int bottom) {
Super.onlayout (changed, left, top, right, bottom);
if (Mheaderview!= null) {
Mheaderview.layout (0, 0, mheaderviewwidth, mheaderviewheight);
Configureheaderview (Getfirstvisibleposition ());
}
}
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
Super.onmeasure (Widthmeasurespec, Heightmeasurespec);
if (Mheaderview!= null) {
Measurechild (Mheaderview, Widthmeasurespec, Heightmeasurespec);
Mheaderviewwidth = Mheaderview.getmeasuredwidth ();
Mheaderviewheight = Mheaderview.getmeasuredheight ();
}
}
public void Setpinnedheaderview (view view) {
Mheaderview = view;
if (Mheaderview!= null) {
Setfadingedgelength (0);
}
Requestlayout ();
}
public void Setadapter (ListAdapter adapter) {
Super.setadapter (adapter);
Madapter = (pinnedheaderadapter) adapter;
}
public void Configureheaderview (int position) {
if (Mheaderview = = null) {
Return
}
int state = madapter.getpinnedheaderstate (position);
Switch (state) {
Case Pinnedheaderadapter.pinned_header_gone: {
Mheaderviewvisible = false;
Break
}
Case Pinnedheaderadapter.pinned_header_visible: {
Madapter.configurepinnedheader (Mheaderview, Position, max_alpha);
if (mheaderview.gettop ()!= 0) {
Mheaderview.layout (0, 0, mheaderviewwidth, mheaderviewheight);
}
Mheaderviewvisible = true;
Break
}
Case PINNEDHEADERADAPTER.PINNED_HEADER_PUSHED_UP: {
View Firstview = getchildat (0);
int bottom = Firstview.getbottom ();
int headerheight = Mheaderview.getheight ();
int y;
int Alpha;
if (bottom < headerheight) {
y = (bottom-headerheight);
Alpha = Max_alpha * (headerheight + y)/headerheight;
} else {
y = 0;
Alpha = Max_alpha;
}
Madapter.configurepinnedheader (Mheaderview, position, Alpha);
if (Mheaderview.gettop ()!= y) {
Mheaderview.layout (0, Y, Mheaderviewwidth, mheaderviewheight
+ y);
}
Mheaderviewvisible = true;
Break
}
}
}
protected void Dispatchdraw (Canvas Canvas) {
Super.dispatchdraw (canvas);
if (mheaderviewvisible) {
Drawchild (Canvas, Mheaderview, Getdrawingtime ());
}
}
}
Next to that fast navigation Bladeview (Blade):
Copy Code code as follows:
public class Bladeview extends View {
Private Onitemclicklistener Monitemclicklistener;
String[] B = {"#", "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"};
int choose =-1;
Paint Paint = new Paint ();
Boolean showbkg = false;
Private Popupwindow Mpopupwindow;
Private TextView Mpopuptext;
Private Handler Handler = new Handler ();
Public Bladeview (context context, AttributeSet attrs, int defstyle) {
Super (context, attrs, Defstyle);
}
Public Bladeview (context context, AttributeSet Attrs) {
Super (context, attrs);
}
Public Bladeview {
Super (context);
}
@Override
protected void OnDraw (Canvas Canvas) {
Super.ondraw (canvas);
if (showbkg) {
Canvas.drawcolor (Color.parsecolor ("#00000000"));
}
int height = getheight ();
int width = getwidth ();
int singleheight = Height/b.length;
for (int i = 0; i < b.length; i++) {
Paint.setcolor (Color.Black);
Paint.settypeface (Typeface.default_bold);
Paint.setfakeboldtext (TRUE);
Paint.setantialias (TRUE);
if (i = = choose) {
Paint.setcolor (Color.parsecolor ("#3399ff"));
}
float xpos = width/2-Paint.measuretext (B[i])/2;
float YPos = singleheight * i + singleheight;
Canvas.drawtext (B[i], xpos, YPos, paint);
Paint.reset ();
}
}
@Override
public boolean dispatchtouchevent (Motionevent event) {
Final int action = Event.getaction ();
Final float y = event.gety ();
Final int oldchoose = choose;
Final int c = (int) (Y/getheight () * b.length);
Switch (action) {
Case Motionevent.action_down:
showbkg = true;
if (Oldchoose!= c) {
if (C > 0 && C < b.length) {
Performitemclicked (c);
choose = C;
Invalidate ();
}
}
Break
Case Motionevent.action_move:
if (Oldchoose!= c) {
if (C > 0 && C < b.length) {
Performitemclicked (c);
choose = C;
Invalidate ();
}
}
Break
Case MOTIONEVENT.ACTION_UP:
showbkg = false;
Choose =-1;
Dismisspopup ();
Invalidate ();
Break
}
return true;
}
private void ShowPopup (int item) {
if (Mpopupwindow = = null) {
Handler.removecallbacks (dismissrunnable);
Mpopuptext = new TextView (GetContext ());
Mpopuptext.setbackgroundcolor (Color.gray);
Mpopuptext.settextcolor (Color.cyan);
Mpopuptext.settextsize (50);
Mpopuptext.setgravity (gravity.center_horizontal
| gravity.center_vertical);
Mpopupwindow = new Popupwindow (mpopuptext, 100, 100);
}
String text = "";
if (item = = 0) {
Text = "#";
} else {
Text = character.tostring ((char) (' A ' + item-1));
}
Mpopuptext.settext (text);
if (mpopupwindow.isshowing ()) {
Mpopupwindow.update ();
} else {
Mpopupwindow.showatlocation (Getrootview (),
Gravity.center_horizontal | gravity.center_vertical, 0, 0);
}
}
private void Dismisspopup () {
Handler.postdelayed (dismissrunnable, 800);
}
Runnable dismissrunnable = new Runnable () {
@Override
public void Run () {
TODO auto-generated Method Stub
if (Mpopupwindow!= null) {
Mpopupwindow.dismiss ();
}
}
};
public boolean ontouchevent (Motionevent event) {
Return Super.ontouchevent (event);
}
public void Setonitemclicklistener (Onitemclicklistener listener) {
Monitemclicklistener = listener;
}
private void performitemclicked (int item) {
if (Monitemclicklistener!= null) {
Monitemclicklistener.onitemclick (B[item]);
ShowPopup (item);
}
}
Public interface Onitemclicklistener {
void Onitemclick (String s);
}
}
The next step is to use the, first declare activity_main.xml in the layout file:
Copy Code code as follows:
<relativelayout 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"
Tools:context= ". Mainactivity ">
<com.way.view.pinnedheaderlistview
Android:id= "@+id/friends_display"
Android:layout_width= "Fill_parent"
android:layout_height= "Fill_parent"
Android:cachecolorhint= "#00000000"
Android:divider= "@null"
Android:footerdividersenabled= "false"
Android:headerdividersenabled= "false"/>
<com.way.view.bladeview
Android:id= "@+id/friends_myletterlistview"
Android:layout_width= "30dip"
android:layout_height= "Fill_parent"
Android:layout_alignparentright= "true"
android:background= "#00000000"/>
</RelativeLayout>
Then there was an independent adapter, and this time I didn't put it in mainactivity as an inner class:
Copy Code code as follows:
public class Friendsadapter extends Baseadapter implements Sectionindexer,
Pinnedheaderadapter, Onscrolllistener {
private int mlocationposition =-1;
Private string[] Mdatas;
First letter Set
Private list<string> mfriendssections;
Private list<integer> mfriendspositions;
Private Layoutinflater Inflater;
Public Friendsadapter (Context context,string[] datas, list<string> friendssections,
List<integer> friendspositions) {
TODO auto-generated Constructor stub
Inflater = Layoutinflater.from (context);
Mdatas = datas;
Mfriendssections = friendssections;
Mfriendspositions = friendspositions;
}
@Override
public int GetCount () {
TODO auto-generated Method Stub
return mdatas.length;
}
@Override
Public Object getitem (int position) {
TODO auto-generated Method Stub
return mdatas[position];
}
@Override
public long getitemid (int position) {
TODO auto-generated Method Stub
return position;
}
@Override
Public View GetView (int position, View Convertview, ViewGroup parent) {
TODO auto-generated Method Stub
int section = getsectionforposition (position);
if (Convertview = = null) {
Convertview = inflater.inflate (R.layout.listview_item, NULL);
}
LinearLayout mheaderparent = (linearlayout) convertview
. Findviewbyid (R.id.friends_item_header_parent);
TextView Mheadertext = (TextView) convertview
. Findviewbyid (R.id.friends_item_header_text);
if (getpositionforsection (section) = = position) {
Mheaderparent.setvisibility (view.visible);
Mheadertext.settext (Mfriendssections.get (section));
} else {
Mheaderparent.setvisibility (View.gone);
}
TextView TextView = (TextView) convertview
. Findviewbyid (R.id.friends_item);
Textview.settext (Mdatas[position]);
return convertview;
}
@Override
public void onscrollstatechanged (Abslistview view, int scrollstate) {
TODO auto-generated Method Stub
}
@Override
public void Onscroll (Abslistview view, int firstvisibleitem,
int visibleitemcount, int totalitemcount) {
TODO auto-generated Method Stub
if (view instanceof Pinnedheaderlistview) {
((Pinnedheaderlistview) view). Configureheaderview (Firstvisibleitem);
}
}
@Override
public int getpinnedheaderstate (int position) {
int realposition = position;
if (Realposition < 0
|| (Mlocationposition!=-1 && mlocationposition = = realposition)) {
return pinned_header_gone;
}
Mlocationposition =-1;
int section = getsectionforposition (realposition);
int nextsectionposition = getpositionforsection (section + 1);
if (nextsectionposition!=-1
&& realposition = = nextSectionPosition-1) {
return pinned_header_pushed_up;
}
return pinned_header_visible;
}
@Override
public void Configurepinnedheader (View header, int position, int alpha) {
TODO auto-generated Method Stub
int realposition = position;
int section = getsectionforposition (realposition);
string title = (string) getsections () [section];
((TextView) Header.findviewbyid (R.id.friends_list_header_text))
. SetText (title);
}
@Override
Public object[] GetSections () {
TODO auto-generated Method Stub
return Mfriendssections.toarray ();
}
@Override
public int getpositionforsection (int section) {
if (Section < 0 | | |-section >= mfriendssections.size ()) {
return-1;
}
return mfriendspositions.get (section);
}
@Override
public int getsectionforposition (int position) {
TODO auto-generated Method Stub
if (Position < 0 | | | position >= getcount ()) {
return-1;
}
int index = Arrays.binarysearch (Mfriendspositions.toarray (), position);
Return index >= 0? Index:-index-2;
}
}
The last is the mainactivity in the process:
Copy Code code as follows:
public class Mainactivity extends activity {
private static final String FORMAT = "^[a-z,a-z].*$";
Private Pinnedheaderlistview Mlistview;
Private Bladeview Mletter;
Private Friendsadapter Madapter;
Private string[] datas;
First letter Set
Private list<string> msections;
Storing data according to the first letter
Private map<string, list<string>> MMap;
First-letter position set
Private list<integer> mpositions;
The position of the first letter
Private map<string, integer> mindexer;
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
InitData ();
Initview ();
}
private void InitData () {
Datas = Getresources (). Getstringarray (r.array.countries);
Msections = new arraylist<string> ();
MMap = new hashmap<string, list<string>> ();
Mpositions = new arraylist<integer> ();
Mindexer = new hashmap<string, integer> ();
for (int i = 0; i < datas.length; i++) {
String firstName = datas[i].substring (0, 1);
if (Firstname.matches (FORMAT)) {
if (Msections.contains (FirstName)) {
Mmap.get (FirstName). Add (Datas[i]);
} else {
Msections.add (FirstName);
list<string> list = new arraylist<string> ();
List.add (Datas[i]);
Mmap.put (FirstName, list);
}
} else {
if (Msections.contains ("#")) {
Mmap.get ("#"). Add (Datas[i]);
} else {
Msections.add ("#");
list<string> list = new arraylist<string> ();
List.add (Datas[i]);
Mmap.put ("#", list);
}
}
}
Collections.sort (msections);
int position = 0;
for (int i = 0; i < msections.size (); i++) {
Mindexer.put (Msections.get (i), position)//in map, key-led letter string, value-headed letter in ListView position
Mpositions.add (position)//The first letter in the ListView position, into the list
Position + = Mmap.get (Msections.get (i)). Size ();//Calculate the position of the next initial letter in ListView
}
}
private void Initview () {
TODO auto-generated Method Stub
Mlistview = (Pinnedheaderlistview) Findviewbyid (R.id.friends_display);
Mletter = (Bladeview) Findviewbyid (R.id.friends_myletterlistview);
Mletter.setonitemclicklistener (New Onitemclicklistener () {
@Override
public void Onitemclick (String s) {
if (Mindexer.get (s)!= null) {
Mlistview.setselection (Mindexer.get (s));
}
}
});
Madapter = new Friendsadapter (this, datas, Msections, mpositions);
Mlistview.setadapter (Madapter);
Mlistview.setonscrolllistener (Madapter);
Mlistview.setpinnedheaderview (Layoutinflater.from (this). Inflate (
R.layout.listview_head, Mlistview, false));
}
}
There is a data arrays.xml, I do not post out, interested friends can download the source code