Android Custom ViewGroup (ii)--Expandablelistview with hover title

Source: Internet
Author: User
Tags gety

In the project to add a click to shrink the expanded list, requires a hover title, specific effects such as:


In other words, when scrolling within a group, the group caption is required to hover, and when the range is rolled out, the header is pulled out and a grouped caption is suspended. Just see a more interesting idea, do a realization, here to share. The code is structured as follows, basically an MVC architecture:


Since is the click can shrink the expansion of the list, obviously to use Expandablelistview, about this class usage here will not repeat, online a search a lot, in fact, with the use of the ListView, but it helps you divided the group, so the original adapter in the GetView () It becomes Getgroupview () and Getchildview (), and GetCount () becomes getgroupcount () and so on. In addition, to support contraction expansion, it is necessary to provide interfaces such as Collapsegroup () and Expandgroup ().

The following analysis of how to add hover title, in fact, the essence of the word: hover the title is painted, rather than add to the view hierarchy, depending on the scrolling situation to determine how to draw.

First, let's write a Dockingexapandablelistview class that inherits from Expandablelistview, which contains a member variable mdockingheader of a view type.

First, rewrite the Onmeasure () and OnLayout () methods

    @Override    protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {        super.onmeasure ( Widthmeasurespec, Heightmeasurespec);        if (Mdockingheader! = null) {            measurechild (Mdockingheader, Widthmeasurespec, heightmeasurespec);            Mdockingheaderwidth = Mdockingheader.getmeasuredwidth ();            Mdockingheaderheight = Mdockingheader.getmeasuredheight ();        }    }    @Override    protected void OnLayout (Boolean changed, int l, int t, int r, int b) {        super.onlayout (changed, L, T, R , b);        if (Mdockingheader! = null) {            mdockingheader.layout (0, 0, mdockingheaderwidth, mdockingheaderheight);}    }
This is a simple measure of the width and height of the title view.

Second, rewrite the Dispatchdraw () method

As mentioned above, hover titles are painted rather than added to the view hierarchy. Therefore, after you finish drawing the other sub-view, draw the hover title bar:

    @Override    protected void Dispatchdraw (canvas canvas) {        super.dispatchdraw (canvas);        if (mdockingheadervisible) {            //Draw header view instead of adding into view hierarchy            drawchild (canvas, Mdockingh Eader, Getdrawingtime ());        }    }

Third, depending on the scrolling state how to draw the hover title

Scrolling to different locations, hover titles are displayed differently, so you need to define a state machine switch based on the scrolling state. Let Dockingexpandablelistview implement the Onscrolllistener interface and override the Onscroll () method:

    @Override public    void Onscroll (abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcount) { C2/>long packedposition = getexpandablelistposition (Firstvisibleitem);        int groupposition = Getpackedpositiongroup (packedposition);        int childposition = Getpackedpositionchild (packedposition);        Update Header view based on first visible item        //Important:refer to Getpackedpositionchild ():        //If this Grou P does not contain a child, returns-1. Need to handle the case in controller.        Updatedockingheader (Groupposition, childposition);    }
Here are some of the more interesting methods, all of which are Expandablelistview's own API:

Getexpandablelistposition (): This API obtains a so-called packed position, which is a 64-bit value, a high 32-bit representation of the group ID, and a low 32-bit representation of the child ID within the group.

Getpackedpositiongroup (): Gets the group ID, which is the high 32-bit

Getpackedpositionchild (): Gets the child ID, which is the low 32-bit

Note that the arguments we give to getexpandablelistposition () are firstvisibleitem, so we get the group that the first visible item at the top and the position within the groups. Next is the most critical Updatedockingheader () method, which determines how the hover title is drawn, based on the state machine. Before looking at this method, let's look at some of the states that are defined in Idockingcontroller:

Public interface Idockingcontroller {    int docking_header_hidden = 1;    int docking_header_docking = 2;    int docking_header_docked = 3;    int getdockingstate (int firstvisiblegroup, int firstvisiblechild);}
There are 3 states, what do these states mean? See:

Docking_header_hidden: When the grouping is not expanded, or there are no children in the group, it is not necessary to draw the hover caption

Docking_header_docking: When scrolling to the last subkey of the previous group, you need to "push" the old title and "Dock" the new title, so this state is named "DOCKING"

Docking_header_docked: The new title "docked" is finished, scrolling inside the grouping, called "docked" state

Based on this state machine, let's take a look at the implementation of the Updatedockingheader () method:

    private void Updatedockingheader (int groupposition, int childposition) {if (getexpandablelistadapter () = = NULL        ) {return;  } if (Getexpandablelistadapter () instanceof Idockingcontroller) {Idockingcontroller Dockingcontroller =            (Idockingcontroller) Getexpandablelistadapter ();            Mdockingheaderstate = Dockingcontroller.getdockingstate (groupposition, childposition); Switch (mdockingheaderstate) {case IDockingController.DOCKING_HEADER_HIDDEN:mDockingHe                    Adervisible = false;                Break Case IDockingController.DOCKING_HEADER_DOCKED:if (Mlistener! = null) {Mlistene                    R.onupdate (Mdockingheader, Groupposition, isgroupexpanded (groupposition));  }//Header view might is "GONE" status at the beginning, so we might is not being able// To get its width and height during initial meAsure procedure.                    Do manual measure and layout operations here.                            Mdockingheader.measure (Measurespec.makemeasurespec (Mdockingheaderwidth, Measurespec.at_most),                    Measurespec.makemeasurespec (Mdockingheaderheight, measurespec.at_most));                    Mdockingheader.layout (0, 0, mdockingheaderwidth, mdockingheaderheight);                    Mdockingheadervisible = true;                Break Case IDockingController.DOCKING_HEADER_DOCKING:if (Mlistener! = null) {Mlisten                    Er.onupdate (Mdockingheader, Groupposition, isgroupexpanded (groupposition));                    } View Firstvisibleview = Getchildat (0);                    int yoffset; if (Firstvisibleview.getbottom () < mdockingheaderheight) {Yoffset = Firstvisibleview.getbottom (                  )-Mdockingheaderheight;  } else {yoffset = 0; }//The Yoffset is always non-positive. When a new header view was "docking",//previous header view need to being "scrolled over".                    Thus we need to draw the//old header view based on last child ' s scroll amount.                            Mdockingheader.measure (Measurespec.makemeasurespec (Mdockingheaderwidth, Measurespec.at_most),                    Measurespec.makemeasurespec (Mdockingheaderheight, measurespec.at_most));                    Mdockingheader.layout (0, Yoffset, mdockingheaderwidth, Mdockingheaderheight + yoffset);                    Mdockingheadervisible = true;            Break }        }    }
Where the hover title is displayed is controlled by a Boolean variable called Mdockingheadervisible, which is also seen in the Dispatchdraw () method above.

Focus on the handling of the "docking" state: By calculating the difference between the bottom and the height of the first visible item, which is the yoffset, determine the offset of the hover title in the y-axis direction. So when we draw the hover title, we can only see part of it, resulting in a feeling of being "rolled out".

Four, hover title state machine

There is a method called Getdockingstate () in the Idockingcontroller interface just mentioned, in the Updatedockingheader () method to determine the state of the current hover caption by calling this method. Dockingexpandablelistviewadapter implements this interface and method to complete state machine state transitions:

    @Override public    int getdockingstate (int firstvisiblegroup, int. firstvisiblechild) {        //No need to draw header vie W If this group does not contain any child & also not expanded.        if (Firstvisiblechild = =-1 &&!mlistview.isgroupexpanded (firstvisiblegroup)) {            return docking_header_ HIDDEN;        }        Reaching current group's last child, preparing for docking next group header.        if (Firstvisiblechild = = Getchildrencount (firstvisiblegroup)-1) {            return idockingcontroller.docking_header_ DOCKING;        }        Scrolling inside current group, header view is docked.        return idockingcontroller.docking_header_docked;    }
The logic is very simple and clear:

If the current group has no subkeys and is not expanded, it returns the Docking_header_hidden state without drawing the hover caption;

If the last subkey of the current group is reached, enter the docking_header_docking state;

In other cases, scroll inside the current group and return to the docking_header_docked state.

Five, Touch event processing

As mentioned earlier in the article, this title view is painted, not added to the view hierarchy, so it is not responsive to touch events! Then we need to make our own judgments based on the click Area, we need to rewrite the onintercepttouchevent () and Ontouchevent () methods:

    @Override public boolean onintercepttouchevent (motionevent ev) {if (ev.getaction () = = Motionevent.action_do            WN && mdockingheadervisible) {rect rect = new Rect ();            Mdockingheader.getdrawingrect (rect); if (rect.contains (int) ev.getx (), (int) ev.gety ()) && mdockingheaderstate = = Idockingcontroller.            docking_header_docked) {//Hit HEADER view area, intercept the touch event return true;    }} return super.onintercepttouchevent (EV); }//Note:as header view is drawn to the canvas instead of adding into view hierarchy,//It's useless to set its T Ouch or click event Listener.    Need to handle these input//events carefully by ourselves. @Override public boolean ontouchevent (motionevent ev) {if (mdockingheadervisible) {rect rect = new            Rect ();            Mdockingheader.getdrawingrect (rect); Switch (ev.getaction ()){Case MotionEvent.ACTION_DOWN:if (rect.contains (int) ev.getx (), (int) ev.gety ())) {                    Forbid event handling by List view ' s item return true;                } break;                    Case MotionEvent.ACTION_UP:long flatpostion = getexpandablelistposition (Getfirstvisibleposition ());                    int grouppos = Expandablelistview.getpackedpositiongroup (flatpostion); if (rect.contains (int) ev.getx (), (int) ev.gety ()) && mdockingheaderstate = = Idockingcon Troller.                        docking_header_docked) {//Handle HEADER View Click event (Do group expansion & collapse)                        if (isgroupexpanded (Grouppos)) {collapsegroup (grouppos);                        } else {expandgroup (grouppos);                        }return true;            } break;    }} return super.ontouchevent (EV); }
This part of the implementation is relatively straightforward, if the current is the docking_header_docked state, and the click Area hit the title view of the drawing rect, then you need to intercept the touch event, and performs a closed or expanded action based on the current state of the group when the finger is lifted.

Vi. Update Title View content

The previous 5 steps have completed the hover title state machine control, but the specific title bar should be displayed (such as changing the title text, display contraction expansion icon, etc.), need the user to handle. Therefore, a Idockingheaderupdatelistener interface is defined, and the user needs to implement the OnUpdate () method to determine how to update the hover caption view based on the current group ID and the shrinking expansion state:

Public interface Idockingheaderupdatelistener {    void onUpdate (View headerview, int groupposition, Boolean expanded) ;}
The implementation of this method in the demo is simply to update the text of the hover title bar, see mainactivity for details.

Vii. Data sources for adapter

This part is actually to dockingexpandablelistviewadapter and sealed a layer of adapter, because some methods have been achieved, The method that needs the user to provide the data is carried out separately to seal a idockingadapterdatasource interface. Of course, you can also use this interface to change the adapter directly, for the sake of completeness of the introduction of the interface is attached here:

Public interface Idockingadapterdatasource {    int getgroupcount ();    int getchildcount (int groupposition);    Object getgroup (int groupposition);    Object getchild (int groupposition, int childposition);    View Getgroupview (int groupposition, Boolean isexpanded, View Convertview, ViewGroup parent);    View Getchildview (int groupposition, int childposition, Boolean islastchild, View Convertview, ViewGroup parent);}


Finally, the most important part of the source code:

Sample code Download (CSDN)

Https://github.com/qianxin2016/DockingExpandableListView

Android Custom ViewGroup (ii)--Expandablelistview with hover title

Related Article

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.