Android Custom view's faux contacts sidebar swipe for a-Z search

Source: Internet
Author: User
Tags drawtext transparent color

Our phone Address book generally has this effect, such as:

OK, this effect everyone has seen more, basically all of the Android phone address book has this effect. So let's see how this works out today.

I. Overview 1. Page function analysis

On the whole, the left is a ListView, the right is a custom view, but the left side of the ListView is a little bit different from the one we normally use, that is, in the ListView I grouped all the contacts, Then the most common way to achieve this effect is two ideas:

1. Use Expandablelistview to achieve this grouping effect

2. Using the normal ListView, implement the Sectionindexer interface when constructing the adapter, and then do the corresponding processing in the adapter

Both of these methods are not difficult, all belong to the use of ordinary control, then here we use the second way to achieve, the first way to implement the method you can self-study, if you are not familiar with the use of Expandablelistview, you can refer to my other two blog:

1. Use Expandablelistview to achieve a time axis

2.android development of the use of Expandablelistview, to achieve similar QQ friends List

OK, this is our left-hand listview implementation idea, right this east is our main character today, here I through a custom view to achieve, view of a, B ... #这些字符我都通过canvas的drawText方法绘制上去. Then override the Ontouchevent method to implement event snooping.

2. The effect to be achieved

To achieve the effect as shown, but you can see the picture in some places may not be very clear, so here I would like to emphasize:

1. The ListView on the left displays the data in groups

2. When the left ListView is sliding, the text color in the right slide control will follow the slide of the left ListView automatically.

3. When the finger is sliding on the right sliding control, the text color of the place where the finger is sliding should change, and there is a textview in the center of the entire page showing the current pressed text of the finger

4. When the finger is pressed to the right of the slide control, the right slide control background turns gray, and when the finger is released, the slide control on the right becomes a transparent color

Two. The implementation of the left ListView grouping effect

No matter how big the project, we have to break it down into small pieces of function to achieve the step, then here we first look at the left of the ListView group implementation, after this effect, we will look at the right of the sliding control how to implement.

First I need to add a ListView to the layout file, which is very simple, exactly the same as the normal ListView, I will not post the code, in addition, for the data set in the ListView, I need to self-build an entity class, the entity class is as follows:

/** * Created by Wangsong on 2016/4/24.    */public class User {private int img;    Private String username;    private String Pinyin;    Private String Firstletter;    Public User () {} public String Getfirstletter () {return firstletter;    } public void Setfirstletter (String firstletter) {this.firstletter = Firstletter;    } public int getimg () {return img;    } public void setimg (int img) {this.img = img;    } public String Getpinyin () {return pinyin;    } public void Setpinyin (String pinyin) {this.pinyin = pinyin;    } public String GetUserName () {return username;    } public void Setusername (String username) {this.username = username;        The public User (string firstletter, int img, string pinyin, string username) {this.firstletter = Firstletter;        This.img = img;        this.pinyin = Pinyin;    This.username = Username; }}

Username used to store user names, IMG represents the user image of the resource ID (here I did not prepare the corresponding picture, we are interested to add their own), pinyin represents the name of the user pinyin, firstletter the first letter of the user name Pinyin, OK, so simple several properties. As for the data source, I added a lot of data in the Strings.xml file, which is not posted here, you can download the source directly at the end of the text to see. Knowing the data source and knowing the entity class, let's look at how to initialize the data in mainactivity:

    private void InitData () {list = new arraylist<> ();        string[] Allusernames = Getresources (). Getstringarray (R.array.arrusernames);            for (String allusername:allusernames) {User user = new User ();            User.setusername (Allusername);            String convert = Chinesetopinyinhelper.getinstance (). Getpinyin (Allusername). toUpperCase ();            User.setpinyin (convert);            String substring = convert.substring (0, 1);            if (Substring.matches ("[A-z]")) {user.setfirstletter (substring);            }else{User.setfirstletter ("#");        } list.add (user); } collections.sort (list, new comparator<user> () {@Override public int compare (User LHS                , User RHS) {if (Lhs.getfirstletter (). Contains ("#")) {return 1;               } else if (Rhs.getfirstletter (). Contains ("#")) {return-1; }else{return Lhs.getfirstletter (). CompareTo (Rhs.getfirstletter ());    }            }        }); }

First, create a list collection to hold all the data, Then read all the data from the Strings.xml file, traverse the data and then store it in the list collection, during the traversal, I pass the tool class chinesetopinyinhelper to Pinyin, and then intercept the first letter of the pinyin, if the letter is A~z, then set directly to U The Firstletter property of the Ser object, otherwise the Firstletter property of the User object is a #, because there are some names in my data source that do not begin with Chinese characters, but names that begin with other characters, so I classify these as # this grouping.

OK, after the data source is constructed, I also need to make a simple sort of list collection, then this sort is the operation in Java, I will not repeat here.

After the data source is constructed, then the adapter of the ListView is constructed, so let's take a look at how this is done, first look at the source code:

/** * Created by Wangsong on 2016/4/24.    */public class Myadapter extends Baseadapter implements Sectionindexer {private list<user> List;    Private context context;    Private Layoutinflater Inflater;        Public Myadapter (context context, list<user> List) {this.context = context;        This.list = list;    Inflater = Layoutinflater.from (context);    } @Override public int getcount () {return list.size ();    } @Override public Object getItem (int position) {return list.get (position);    } @Override public long getitemid (int position) {return position;        } @Override public View getView (int position, view Convertview, ViewGroup parent) {Viewholder holder;            if (Convertview = = null) {Convertview = inflater.inflate (R.layout.listview_item, NULL);            Holder = new Viewholder ();            Holder.showletter = (TextView) Convertview.findviewbyid (r.id.show_letter); Holder.usernamE = (TextView) Convertview.findviewbyid (r.id.username);        Convertview.settag (holder);        } else {holder = (Viewholder) convertview.gettag ();        } User user = List.get (position);        Holder.username.setText (User.getusername ());        Gets the current position which is belonging to which grouping int sectionforposition = getsectionforposition (position);        position int positionforsection = getpositionforsection (sectionforposition) for the first item of the grouping;            See if the current position is the first item in the group that contains the current item///If it is, then show showletter, otherwise hide if (position = = Positionforsection) {            Holder.showLetter.setVisibility (view.visible);        Holder.showLetter.setText (User.getfirstletter ());        } else {holder.showLetter.setVisibility (view.gone);    } return Convertview;    } @Override Public object[] GetSections () {return new object[0]; }//Pass in a grouping value [a .... Z], get the first item of the group position @Override public int getpositionforsection (int sectionindex{for (int i = 0; i < list.size (); i++) {if (List.get (i). Getfirstletter (). charAt (0) = = Sectioninde            x) {return i;    }} return-1; }//Pass in a position to get the group where the position is located @Override public int getsectionforposition (int position) {return LIST.G    ET (position). Getfirstletter (). charAt (0);    } class Viewholder {TextView username, showletter; }}

Most of this adapter is still the same as our previous adapter, but here to implement the Sectionindexer interface, the implementation of this interface, we will implement the interface of the three methods, respectively, is getsections (), Getpositionforsection (), getsectionforposition () These three methods, which we use here are mainly the following two methods, then I would say in detail:

1.getPositionForSection (int sectionindex)

This method takes a parameter of type int, which actually refers to our grouping, where we pass in the grouped value "A ...". Z ", then we return the position of the first item in the group by its own calculation in the method.

2.getSectionForPosition (int position)

This method takes a parameter of type int, which is actually the position of the item that our ListView is about to display, and we pass this position to get the group to which the position item belongs, and then return the value of this grouping.

Having said so much, you may have questions, why should I implement this interface? Let's take a look at the layout file for my item:

<?xml version= "1.0" encoding= "Utf-8"? ><linearlayout xmlns:android= "http://schemas.android.com/apk/res/ Android "Android:layout_width=" Match_parent "android:layout_height=" Match_parent "a ndroid:orientation= "vertical" > <textview android:id= "@+id/show_letter" android:layout_width= "Match_        Parent "android:layout_height=" wrap_content "android:layout_margintop=" 3DP "/> <relativelayout Android:layout_width= "Match_parent" android:layout_height= "Wrap_content" > <imageview Android Oid:id= "@+id/userface" android:layout_width= "72DP" android:layout_height= "72DP" android:p            adding= "12DP" android:src= "@mipmap/ic_launcher"/> <textview android:id= "@+id/username" Android:layout_width= "Wrap_content" android:layout_height= "Match_parent" Android:layout_c Entervertical= "true" android:layout_marginleft= "36DP" android:layout_torightof= "@id/userface" android:gravity= "center" android:text= "username"/> </RelativeLayout></LinearLayout>

In my item's layout file, all of my item is actually the same, there is a textview that shows the grouped data, so I need to determine whether the TextView of the displayed grouping is hidden from the GetView method of the adapter, depending on the item displayed. So we go back to look at my ListView in the GetView method, GetView front of the wording of nothing to say, and the ordinary ListView are the same, we mainly to look at these lines:

Gets the current position which is belonging to which grouping        int sectionforposition = getsectionforposition (position);        Position        int positionforsection = getpositionforsection (sectionforposition) for the first item of the grouping;        See if the current position is the first item in the group that contains the current item        ///If it is, then show showletter, otherwise hide        if (position = = positionforsection) {            Holder.showLetter.setVisibility (view.visible);            Holder.showLetter.setText (User.getfirstletter ());        } else {            holder.showLetter.setVisibility (view.gone);        }

I first determine which item is currently displayed in which group, and then get the position of the first item in the group, and finally determine whether the position of the item I am currently displaying is the first item in the group it is in, and if so, Then will showletter this textview display, simultaneously displays the corresponding grouping information, otherwise will this showletter hides. It's that simple. After we've done this, we'll simply add two lines of code to the activity:

ListView ListView = (ListView) Findviewbyid (r.id.lv);        Myadapter adapter = new Myadapter (this, list);        Listview.setadapter (adapter);

At this point the left side of the group ListView can be displayed. It's that simple.

Three. Implementation of the right slide control

The one on the right is obviously a custom view, so let's take a look at this custom view.

First, this custom control inherits from the view, inherits from the view, needs to implement its inside construction method, about these three constructs the method explanation everybody can view my another blog The Android custom View the clock birth record, here for constructs the method I not to repeat. In this custom view, I need to first declare 5 variables, as follows:

    The position of the current finger sliding to the    private int choosedposition =-1;    Draw the brush of the text of the    private paint paint;    All text on the right is    private string[] letters = new string[]{"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", "#"};    The TextView in the center of the page to show the text where the finger is currently sliding to the    private TextView textviewdialog;    Interface variable, which is used primarily to implement the ListView to scroll the private Updatelistview updatelistview when the finger slides on the right sliding control    ;

The role of the five variables I have said in the comments in detail. OK, after the variable declaration is complete, I also initialize some variables, the initialization of the variables is of course in the construction method to proceed:

Public Letterindexview (context context, AttributeSet attrs, int defstyleattr) {        Super (context, attrs, defstyleattr) ;        Paint = new paint ();        Paint.setantialias (true);        Paint.settextsize ();    }

OK, the only thing to initialize here is actually paint a variable.

After the preparation is done, the next step is OnDraw, the code is as follows:

    @Override    protected void OnDraw (canvas canvas) {        int pertextheight = getheight ()/letters.length;        for (int i = 0; i < letters.length; i++) {            if (i = = choosedposition) {                paint.setcolor (color.red);            } else { C7/>paint.setcolor (Color.Black);            }            Canvas.drawtext (Letters[i], (getwidth ()-Paint.measuretext (Letters[i])/2, (i + 1) * pertextheight, paint);        }    }

At the time of drawing, I need to get the space of each piece of text first, the usable height of each text should be the total height divided by the total number of words, then, through a for loop 26 letters are all drawn out. In the painting, if the text is located exactly where my finger is pressed, then the color of the text is red, or black, the last drawtext do not need me to say it.

After the drawing is done, the ontouchevent is rewritten as follows:

    @Override public boolean ontouchevent (Motionevent event) {int pertextheight = GetHeight ()/letters.length;        Float y = event.gety ();        int currentposition = (int) (y/pertextheight);        String letter = Letters[currentposition];                Switch (event.getaction ()) {case MotionEvent.ACTION_UP:setBackgroundColor (color.transparent);                if (textviewdialog! = null) {textviewdialog.setvisibility (view.gone);            } break;                Default:setbackgroundcolor (Color.parsecolor ("#cccccc")); if (currentposition > 1 && currentposition < letters.length) {if (Textviewdialog! = nul                        L) {textviewdialog.setvisibility (view.visible);                    Textviewdialog.settext (letter); } if (Updatelistview! = null) {UPDATELISTVIEW.UPDATELISTVIEW (letter);                } choosedposition = currentposition;        } break;        } invalidate ();    return true; }

For the action of the right slide control I can be divided into two parts, the finger lift is divided into one category, all other operations are classified as one category. So when the control senses the action event of my finger, it first needs to know what is the item that my finger is currently clicked on, so how can I get this value? I can get the y-coordinate of the position of the finger, then divide by the height of each text, know the position of the current finger click Position, then read the corresponding value from the letters array. Knowing the current click on which letter, the rest of the work is very simple, modify the background color of the control, and then display the corresponding letter on the TextView, then the current position to choosedposition, and finally call invalidate () method to redraw the control. The corresponding text color also changes because the value of choosedposition has changed since the control was redrawn. In addition, I hope that the finger on the right side of the control sliding, the ListView can also follow the scroll, this is no doubt the use of interface callback, the specific people look at the code, simple things do not repeat. Finally, I hope that when the ListView scrolls, the color of the text in the right control should be updated in real time, then this is also very simple, in the custom view to expose a method, as follows:

    public void Updateletterindexview (int currentchar) {for        (int i = 0; i < letters.length; i++) {            if (Currentchar = = Letters[i].charat (0)) {                choosedposition = i;                Invalidate ();                Break;}}}    

Finally, take a look at the current code in activity:

TextView TextView = (TextView) Findviewbyid (r.id.show_letter_in_center);        Final Letterindexview Letterindexview = (letterindexview) Findviewbyid (R.id.letter_index_view);        Letterindexview.settextviewdialog (TextView); Letterindexview.setupdatelistview (New Letterindexview.updatelistview () {@Override public void Updat Elistview (String currentchar) {int positionforsection = adapter.getpositionforsection (Currentchar.charat (0                ));            Listview.setselection (positionforsection);        }        }); Listview.setonscrolllistener (New Abslistview.onscrolllistener () {@Override public void Onscrollstat Echanged (abslistview view, int scrollstate) {} @Override public void Onscroll (Abslistvie W view, int firstvisibleitem, int visibleitemcount, int totalitemcount) {int sectionforposition = adapter.                Getsectionforposition (Firstvisibleitem); LetterIndexview.updateletterindexview (sectionforposition); }        });

It's that simple.


SOURCE Download http://download.csdn.net/detail/u012702547/9501208


Above.

Android Custom view's faux contacts sidebar swipe for a-Z search

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.