Android UI Design Series custom ListView imitation QQ space damping Drop-down Refresh and Gradient menu bar effects (8) _android

Source: Internet
Author: User
Tags abs static class xmlns

Haven't written about UI for a long time, just turned over the previous blog, a recent blog about the UI: the Android UI Design series of the custom dialog implementation of various styles of dialog box effect (7), to achieve a variety of style effects of the dialog box, After that blog after writing because the company closed the development of the network and other reasons that caused the blog interruption so far, the interruption so long is very ashamed, follow-up I will try to write all add out. Recently, the project has a need to do a and QQ space similar to the menu bar transparency gradient and drop-down refresh with a damping rebound effect. So spend some time to try, basically reached the QQ space effect, screenshot as follows:

By observing the running effect of QQ space, it is found that when the menu bar is scrolled up, the transparency component increases until it is completely opaque and the opacity becomes transparent. When scrolling to the top to continue to pull down will appear pulling effect when loose after the damping rebound effect. So by rewriting ListView imitate the operation of QQ space effect.
Two questions need to be considered before implementing the QQ space operation effect:
1, how to implement the menu bar transparency gradient
by observing the running effect of QQ space, we can see that the transparency of the menu bar is dynamically changing according to the rolling distance, and the listview of the rolling distance need to be known to realize the change of the transparency, so the question about the transparency is transformed into the problem of rolling distance.
2), how to achieve resistance Nila and rebound effect
To use ListView to achieve the damping effect requires the ListView to first scroll to the top, when ListView scroll to the top, if the continuation of manual decline requires its first child changes to simulate the pull effect, when the finger released after the child to bounce back to the initial state.
Let's start with the first question: to achieve a transparency gradient, we first get the scrolling distance of the ListView and calculate the corresponding transparency by scrolling distance. Because the ListView multiplexing mechanism determines that the scrolling value cannot be obtained by the GetTop () method of the first visible item, we can get the scrolling distance by Headerview because the header is not involved in the reuse in the ListView.
Let's take a look at the scrolling process after ListView add Headerview:

The diagram above roughly draws the three scrolling states where the ListView contains Headerview, the state one can be called the initial state or just scroll to the top state, at which point the Headerview gettop () value is 0; State two is the scroll state of ListView, At this point, the Headerview does not completely scroll out of the ListView boundary, and GetTop () has a negative return value between 0 and Headerview; State three indicates that the Headerview has completely scrolled out of the ListView boundary, If the return value obtained by the call to GetTop () is negative and the absolute value equals the height of the Headerview (thereafter it can be understood that Headerview is fixed at the top of the ListView).
        understand the rolling principle of ListView, we first try to implement the function of the gradient menu bar. First of all define their own ListView, named Flexiblelistview, the word flexible is flexible, diverse meaning, because our ListView not only to achieve the menu bar transparency gradient also to achieve damping effect, So it is more appropriate to name Flexiblelistview. After Flexiblelistview inherits ListView, you need to implement its construction method, as follows:

 public class Flexiblelistview extends ListView {public Flexiblelistview (context con 
 Text) {super (context); 
 Public Flexiblelistview (context, AttributeSet attrs) {Super (context, attrs); Flexiblelistview (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, Defstyleatt 
 R); 
 @TargetApi Public Flexiblelistview (context context, AttributeSet attrs, int defstyleattr, int defstyleres) { 
 Super (context, Attrs, defstyleattr, defstyleres); } 
} 

The

        Flexiblelistview only Inherits ListView, which is essentially no different from ListView. Now that we're judging the scrolling distance by adding Headerview to ListView, we're going to get the Headerview object. How do I get the Headerview object? Here's the trick, because adding Headerview to ListView ultimately calls ListView's Addheaderview (View V, Object data, Boolean isselected) method, so we can rewrite the method, Take the first headerview to add in, how to judge is the first to add in Headerview? Because the addition of the Headerview is ordered, first to be added first to draw. So you can define a property mheaderview that represents the first Headerview, and when you call to the Addheaderview () method, by determining whether the Mheaderview value is null or not, if you assign a value if it is null, the code is as follows:

 public class Flexiblelistview extends ListView {private View mheaderview; 
 
 private int mmaxscrollheight; 
 Public Flexiblelistview {Super (context); 
 Public Flexiblelistview (context, AttributeSet attrs) {Super (context, attrs); Flexiblelistview (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, Defstyleatt 
 R); 
 @TargetApi Public Flexiblelistview (context context, AttributeSet attrs, int defstyleattr, int defstyleres) { 
 Super (context, Attrs, defstyleattr, defstyleres); @Override public void Addheaderview (View V, Object data, Boolean isselectable) {Super.addheaderview (V, data, are 
 selectable); 
 if (null = = Mheaderview) {Mheaderview = v; 
 Mmaxscrollheight = Mheaderview.getlayoutparams (). Height; } 
 } 
} 

The Mheaderview and Mmaxscrollheight properties are defined in the

         Flexiblelistview. In the Addheaderview () method, Mheaderview is made to obtain the first Headerview and assign to mheadereview,mmaxscrollheight the maximum scrolling distance of the Headerview. When the Headerview scroll distance exceeds this value we will set the menu bar opaque or change the transparency. Here I use the headerview height directly to indicate the maximum distance it allows to scroll.
        can now get the first headerview of ListView, and the next step is to judge ListView's scrolling, At this time some child boots may think of the way to add Scrolllistener to ListView, this way is feasible, but we do not use the way to add listener, If you are familiar with the ListView source code, it is clear that the trigger Onitemscrolllistener callback timing is in the Abslistview Invokeonitemscrolllistener () method, the source code is as follows:

/** * Notify our scroll listener (if there are one) of a change in scroll state */V OID Invokeonitemscrolllistener () {if (Mfastscroll!= null) {Mfastscroll.onscroll (mfirstposition, Getchildcount (), MI 
 Temcount); 
 } if (Monscrolllistener!= null) {Monscrolllistener.onscroll (this, mfirstposition, Getchildcount (), mitemcount); } onscrollchanged (0, 0, 0, 0); 
Dummy values, View ' s implementation does not. } 

The

        Invokeonitemscrolllistener () method triggers a scrolling callback. Whether we give ListView settings Onitemscrolllistener that this method will call, the attentive classmate may find that the method at the end of the call to view the Onscrollchanged () method, then you suddenly realize that we can rewrite the method, When the listview happened to scroll also called the Onscrollchange () method, more convenient AH. Oh, congratulations, right, we are today using the rewrite onscrollchanged () method to set the transparency of the menu bar by judging the scrolling distance of the ListView Headerview.
        Now we know the rolling time of the ListView, the Headerview and the maximum rolling distance, The next step is to analyze the conditions for implementing the gradient: to achieve a gradient we need to know who is going to be the gradient, in our app may be actionbar, or maybe toolbar, or maybe a custom viewgroup to simulate Actionbar, So Flexiblelistview has to represent the Mactionbar attribute of Actionbar and provide a method Bindactionbar (), which means that the actionbar that needs to implement the gradient is passed in, and the code is as follows:

public class Flexiblelistview extends ListView {private View mactionbar; 
 Private View Mheaderview; 
 private int mmaxscrollheight; 
 
 Private drawable Mactionbarbackground; 
 Public Flexiblelistview {Super (context); 
 Public Flexiblelistview (context, AttributeSet attrs) {Super (context, attrs); Flexiblelistview (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, Defstyleatt 
 R); 
 @TargetApi Public Flexiblelistview (context context, AttributeSet attrs, int defstyleattr, int defstyleres) { 
 Super (context, Attrs, defstyleattr, defstyleres); @Override protected void onscrollchanged (int l, int t, int oldl, int Oldt) {super.onscrollchanged (L, T, OLDL, O 
 LDT); 
 if (null!= mactionbarbackground) {Mactionbarbackground.setalpha (Evaluatealpha math.abs (Mheaderview.gettop ())); @Override public void Addheaderview (View V, Object data, Boolean isselectable) {Super.addheaDerview (V, data, isselectable); 
 if (null = = Mheaderview) {Mheaderview = v; 
 Mmaxscrollheight = Mheaderview.getlayoutparams (). Height; 
 } private int Evaluatealpha (int t) {if (T >= mmaxscrollheight) {return 255; 
 return (int) (255 * t/(float) mmaxscrollheight); 
 } public void Bindactionbar (View actionbar) {if (null!= actionbar) {mactionbar = Actionbar; 
 Mactionbarbackground = Actionbar.getbackground (); 
 if (null = = Mactionbarbackground) {mactionbarbackground = new colordrawable (color.transparent); 
 } mactionbarbackground.setalpha (0); 
 if (Build.VERSION.SDK_INT >=) {mactionbar.setbackground (mactionbarbackground); 
 else {mactionbar.setbackgrounddrawable (mactionbarbackground); }} public void Bindactionbar (Actionbar actionbar) {if (null!= actionbar) {//TODO impl with Actionbar/ 
 /actionbar.setbackgrounddrawable ();  } 
 } 
}

The

        flexiblelistview new Mactionbar and Mactionbarbackground properties. Mactionbar represents the menu bar that requires a gradient, mactionbarbackground the background of the menu bar. Second, the overloaded Method Bindactionbar () is provided externally, and the Actionbar method is an empty implementation, where a TODO prompt is added and a setbackgrounddrawable () hint is given ( Note that Actionbar is required to implement a gradient windowfeature), hope that children can realize their own. The Onscrollchanged () method is overridden in the
        Flexiblelistview. The calculation of Evaluatealpha () is simple in this method by obtaining the GetTop () value of Mheaderview and then invoking the Evaluatealpha () method to calculate the alpha value. When the scroll value exceeds the maximum scrolling distance mmaxscrollheight returns 255 (255 is opaque, 0 is transparent), otherwise the current scrolling value corresponds to the alpha value, and finally by calling Mactionbarbackground's Setalpha () To achieve mactionbar changes in transparency.
        now logically ready to implement the transparency of the menu bar, let's test it and define the menu bar layout with the following code:

 <?xml version= "1.0" encoding= "Utf-8"?> <framelayout "xmlns:android=" Schemas.android.com/apk/res/android "android:layout_width=" match_parent "android:layout_height=" @dimen/action_ Bar_height "android:background=" #aabbcc "android:clickable= true" android:orientation= "vertical" android:paddingle ft= "10DP" > <textview android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Android:layo Ut_gravity= "center_vertical" android:drawableleft= "@mipmap/back" android:text= "dynamic" android:textcolor= "#b8e7fe" and 
 Roid:textsize= "17sp"/> <textview android:layout_width= "wrap_content" android:layout_height= "Wrap_content" android:layout_gravity= "center" android:text= "friend dynamic" android:textcolor= "#b8e7fe" android:textsize= "17SP"/> &L T;/framelayout> 

The menu bar contains a return button and a caption, with a fixed height and background color for the menu bar, and then layout our Activity_main.xml file with the following code:

<?xml version= "1.0" encoding= "Utf-8"?> <framelayout 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" > 
 
 <com.llew.wb.git.qqzone.flexiblelistview 
 android:id= "@+id/ Flexible_list_view " 
 android:layout_width=" match_parent " 
 android:layout_height=" Match_parent 
 " Android:scrollbars= "None" ></com.llew.wb.git.qqzone.FlexibleListView> 
 
 <include 
 android:id = "@+id/custom_action_bar" 
 layout= "@layout/action_bar_layout"/> 
</FrameLayout> 

The Activity_main.xml layout file is simple, using the framelayout root layout to let the menu bar hover over the Flexiblelistview, and then write our mainactivity code as follows:

public class Mainactivity extends Appcompatactivity {private Flexiblelistview mlistview; 
 @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); 
 
 Setcontentview (R.layout.activity_main); 
 Initglobalparams (); 
 
 private void Initglobalparams () {Mlistview = (Flexiblelistview) Findviewbyid (R.id.flexible_list_view); 
 View Mflexibleheaderview = new View (Getapplicationcontext ()); 
 Mflexibleheaderview.setbackgroundcolor (Color.parsecolor ("#bbaacc")); 
 int height = getresources (). Getdimensionpixelsize (R.dimen.header_height); 
 Layoutparams params = new Layoutparams (layoutparams.match_parent, height); 
 
 Mflexibleheaderview.setlayoutparams (params); 
 
 Final View Actionbar = Findviewbyid (R.id.custom_action_bar); 
 Mlistview.bindactionbar (Actionbar); 
 
 Mlistview.addheaderview (Mflexibleheaderview); 
 Mlistview.setadapter (New Adapter ()); Static Class Adapter extends Baseadapter {@Override public int getcount (){return 80; 
 @Override public Object getitem (int position) {return null; 
 @Override public long getitemid (int position) {return 0; @Override public View getview (int position, View Convertview, ViewGroup parent) {TextView TextView = new TEXTVI 
 EW (Parent.getcontext ()); 
 Textview.setpadding (50, 50, 50, 50); 
 Textview.settext (position + 10 + ""); 
 return textView; 
 } 
 } 
}

In Mainactivity, Flexiblelistview is added a header with a fixed height background color of "#bbaacc", and the suspension menu bar Actionbar assigned to Flexiblelistview Mactionbar, Finally set adapter, in order to test the code write very simple, we run a program to see the effect:

See the effect of good happy Ah, (*^__^*) ... The transparency gradient function is up to our expectations, and then the damping effect begins, and the damping effect is that when the ListView rolls to the top, if it continues to slide, the ListView can continue to scroll a little farther down the listview to restore the original position after the finger leaves the screen. In order to achieve this function, some child boots may think of rewriting the onxxxevent () and other methods of event transmission, then the motionevent for Down,move,up or cancel, respectively, to make logical judgments to achieve damping effect, this way is feasible, But it's a lot more complicated than our implementation today ...
The implementation of the damping effect here is to use the view of the Overscrollby () method, some children's boots may ask the Overscrollby () method is 2.3 version before the increase, 2.3 version before the compatibility How to do? I have also considered this before implementing this feature, on the one hand, our company's app only supports more than 3.0 version, on the other hand 2.3 and previous versions of the market share is almost negligible, so you can consider no longer compatible with the previous version of 2.3.
Some students may be unfamiliar with the Overscrollby () method, the first general say the method, its source code is as follows:

/** * Scroll The view with standard behavior for scrolling beyond the normal * content boundaries. Views so call this is should override * {@link #onOverScrolled (int, int, Boolean, Boolean)} to respond to the * 
 Results of an over-scroll operation. 
 * * Views can be use this and handle any touch or fling-based scrolling. * * @param deltax change in X in pixels * @param deltay change in Y in pixels * @param scrollx current X scroll Valu E in pixels before applying deltax * @param scrolly current Y scroll value in pixels before applying deltay * @param s  Crollrangex Maximum content Scroll range along the X axis * @param scrollrangey Maximum content Scroll range along the Y 
 Axis * @param maxoverscrollx number of pixels to overscroll by in either direction * along the X axis. 
 * @param maxoverscrolly number of pixels to overscroll by in either direction * along the Y axis. * @param istouchevent True if this scroll operation be the result ofEvent. 
 * @return True if scrolling is clamped to a over-scroll boundary along either * axis, False otherwise. * * @SuppressWarnings ({"Unusedparameters"}) protected Boolean overscrollby (int deltax, int deltay, int scrollx, int scrol 
 LY, int scrollrangex, int scrollrangey, int maxoverscrollx, int maxoverscrolly, Boolean istouchevent) {//...}

Read the source to see the note is important, we first look at the comments, the general meaning is as follows:
When the view component scrolls to the boundary, the previous scrolling action is also continued (Note: This method is not triggered when scrolling to the boundary), and if the view component calls the method, the view component should override the Onoverscrolled () method to respond to the over-scroll action. The view control can call this method to handle any touch scrolling or fast sliding. Feel the translation of good awkward, said the straightforward point is when the listview,scrollview, such as rolling to the end if the continued decline will call the method.
The Overscrollby () method has 9 parameters, each of which is described in detail, and we only look at the two parameters that need to be used DeltaY and istouchevent;deltay represent the relative values that are scrolled on the y-axis. For example, ListView scroll to the top if you continue to pull down, the DeltaY value is negative, when it scrolls to the bottom when we continue to pull up, the DeltaY value is positive, so we can judge according to DeltaY ListView is pull or pull operation, Istouchevent is true to indicate that the finger is touching the screen or leaving the screen.
Understanding the Overscrollby () method begins to implement the damping effect, the core is to rewrite the Overscrollby () method, in this method dynamically changing the height of headerview, if the fingers loose we will restore Headerview. We know that QQ space at the top is a picture, the moment pull the picture has the elasticity of the effect, when the finger released after the picture and telescopic back, so we directly use ImageView simulation of this effect. Analog image damping allows ImageView to be match_parent (headerview height changes after ImageView height can also change), this time also set ImageView ScaleType for Center_ Crop (unclear ImageView ScaleType attributes refer to a blog post I wrote earlier: the Android source < > from the source perspective to understand the ScaleType properties of ImageView in depth).
Now begin to rewrite the Overscrollby () method in Flexiblelistview, as follows:

 @Override protected Boolean Overscrollby (int deltax, int deltay, int scrollx, int scrol LY, int scrollrangex, int scrollrangey, int maxoverscrollx, int maxoverscrolly, Boolean istouchevent) {if (null!= mhead 
 Erview) {if (istouchevent && DeltaY < 0) {Mheaderview.getlayoutparams (). Height + = Math.Abs (deltay/3.0); 
 Mheaderview.requestlayout (); } return Super.overscrollby (DeltaX, DeltaY, Scrollx, scrolly, Scrollrangex, Scrollrangey, MAXOVERSCROLLX, MAXOVERSCR 
Olly, Istouchevent); } 

        Overscrollby () In this method, we change the height of the mheaderview dynamically according to the DeltaY value and rearrange the imageview height, note: The height is calculated with the DeltaY divided by 3, at which point the 3 represents the growth factor, and the goal is to allow Headerview to grow slowly , you can provide a way to set this value externally.
        now only implements the Headerview pull function, but has not implemented the zoom function, because the Overscrollbay () is implemented by the finger touch of the Drop-down, When the finger leaves the screen to perform a headerview recovery operation, we can consider the type of motionevent in the Ontouchevent () method and restore the Headerview when it is up or cancel. The recovery Headerview cannot be undone at once but in an animated way, so that it looks more natural, so the ontouchevent () code is as follows:

 @Override public boolean ontouchevent (motionevent ev) {if (null!= mheaderview) {i 
 NT action = Ev.getaction (); if (motionevent.action_up = ACTION | | 
 Motionevent.action_cancel = = ACTION) {resetheaderviewheight (); 
} return super.ontouchevent (EV); 
 private void Resetheaderviewheight () {Valueanimator valueanimator = valueanimator.ofint (1); 
 Valueanimator.setduration (700); Valueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void onanimationupdate (Valueanimator animation) 
 {final float F = animation.getanimatedfraction (); 
 Mheaderview.getlayoutparams (). Height-= f * (Mheaderview.getlayoutparams (). Height-mmaxscrollheight); 
 
 Mheaderview.requestlayout (); 
 } 
 }); 
 Valueanimator.setinterpolator (New Overshootinterpolator ()); 
Valueanimator.start (); } 

        Headerview Restoration Animation We used the Valueanimator, We change the value of Headerview dynamically during the execution of the animation to achieve the gradient effect. Next layout Headerview to simulate QQ space, the code is as follows:

<?xml version= "1.0" encoding= "Utf-8"?> <framelayout xmlns:android= "http://schemas.android.com/apk/res/" Android "Android:layout_width=" Match_parent "android:layout_height=" @dimen/header_height "> <imageview andr Oid:id= "@+id/iv" android:layout_width= "match_parent" android:layout_height= "Match_parent" android:scaleType= " Centercrop "android:src=" @mipmap/ttt "/> <linearlayout android:layout_width=" Match_parent "Android:layout_ height= "30DP" android:layout_gravity= "Bottom" android:background= "#33333333" android:gravity= "center_vertical" and roid:orientation= "Horizontal" > <textview android:layout_width= "0dp" android:layout_height= "Match_parent" a 
 
 ndroid:layout_weight= "1" android:text= "album" android:gravity= "Center" android:textcolor= "@android: Color/white"/> <view android:layout_width= "1DP" android:layout_height= "20DP" android:background= "#ffffff"/> <Text View android:layout_width= "0DP" Android:layout_height= "Match_parent" android:layout_weight= "1" android:text= "Say" android:gravity= "center" Android:textC Olor= "@android: Color/white"/> <view android:layout_width= "1DP" android:layout_height= "20DP" android:backg round= "#ffffff"/> <textview android:layout_width= "0DP" android:layout_height= "Match_parent" android:layou  
 t_weight= "1" android:text= "personalized" android:gravity= "center" android:textcolor= "@android: Color/white"/> <view Android:layout_width= "1DP" android:layout_height= "20DP" android:background= "#ffffff"/> <textview Andro Id:layout_width= "0DP" android:layout_height= "Match_parent" android:layout_weight= "1" android:text= "\@ related to Me" Androi 
 d:gravity= "center" android:textcolor= "@android: Color/white"/> </LinearLayout> </FrameLayout>

The

        headerview layout allows ImageView's width to be set to Match_ Parent and set the ScaleType to Centercrop. Modify the Mainactivity Initglobalparams () method with the following code:

void Initglobalparams () { 
 Mlistview = (flexiblelistview) Findviewbyid (R.id.flexible_list_view); 
 View Mflexibleheaderview = Layoutinflater.from (this). Inflate (R.layout.flexible_header_layout, MListView, false); 
 Abslistview.layoutparams params = (abslistview.layoutparams) mflexibleheaderview.getlayoutparams (); 
 if (null = = params) { 
 params = new Abslistview.layoutparams (AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT); 
 } 
 Params.height = Getresources (). Getdimensionpixelsize (r.dimen.header_height); 
 Mflexibleheaderview.setlayoutparams (params); 
 
 Final View Actionbar = Findviewbyid (R.id.custom_action_bar); 
 
 Mlistview.bindactionbar (Actionbar); 
 Mlistview.addheaderview (Mflexibleheaderview); 
 
 Mlistview.setadapter (New Adapter ()); 
} 

OK, everything is ready, hurriedly run the program, see the Effect Bar (*^__^*) ...

Well, it looks good.
OK, about the implementation of the QQ space of the damping Drop-down refresh and Gradient menu bar is over, mainly using the 2.3 version of the Overscrollby () method (if you want to be compatible with the previous version of 2.3, the children need to implement the relevant logic of the boot) Secondly, the ScaleType property of ImageView is fully used to simulate the effect of the damping springback of QQ space picture. Thanks again for watching (*^__^*) ...

Original link: http://blog.csdn.net/llew2011/article/details/51559694

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.