Android listview pull-down refresh control implementation

Source: Internet
Author: User

Android pull-down refresh, which is currently used by many applications.

For example, pull down Weibo to refresh more data.

In general, the listview we are using implements a drop-down to obtain more data. It is only the listener that pulls the end Of the listview when this pull-down refresh operation is performed.

For listview refresh, there are two scenarios:

1. Get more data and store the data in the chronological order of the server database. At this moment, we get the data that is shown earlier in our application, which is also the most common situation.

For example, Weibo obtains more information, that is, it obtains more earlier information and dynamically adds it to the bottom of existing data );

2. Getting more latest data is actually a way to get more operations. However, this mainly takes into account the user's operation habits. Generally, there are two types of user operation habits:

First, get the next page, second, similar to the F5 refresh of the webpage, staying on the refresh of the current page.

Refreshing a listview is similar to refreshing a webpage. If no pull-down refresh is used, you have to drag the listview to the end (of course, you can also add a refresh button control at the top of the interface, but the interface is not very large for mobile phones, this design should not be too much .), If there is too much data, you need to pull down to the very bottom to perform a refresh. In most users' habits, after obtaining more up-to-date information, they are expected to be highlighted at the top of the interface. That is to say, the user still prefers the lazy operation and completes all the operations on the same display interface. Then, pull-down refresh is a good design.

: Normal

Pull-down Refresh:

This is the basic effect.

Custom Control Code

/*** Refresh control view *** @ author Nono **/public class refreshableview extends linearlayout {Private Static final string tag = "Lilith"; private scroller scroler; private view refreshview; private imageview refreshindicatorview; private int refreshtargettop =-60; private progressbar bar; private textview downtextview; private textview timetextview; private refreshlistener; private string downtex Tstring; private string releasetextstring; private long refreshtime = NULL; private int lastx; private int lasty; // pull flag private Boolean isdragging = false; // whether to refresh private Boolean isrefreshenabled = true; // Private Boolean isrefreshing = false; private context mcontext; Public refreshableview (context) {super (context ); mcontext = context;} public refreshableview (context, attributeset Attrs) {super (context, attrs); mcontext = context; Init ();} private void Init () {// todo auto-generated method stub // slide object, scroller = new scroller (mcontext); // refresh the view refreshview at the top of the view = layoutinflater. from (mcontext ). inflate (R. layout. refresh_top_item, null); // indicator view refreshindicatorview = (imageview) refreshview. findviewbyid (R. id. indicator); // refresh Barbar = (progressbar) refreshview. findviewbyid (R. id. pro Gress); // The text downtextview = (textview) refreshview is displayed in the drop-down list. findviewbyid (R. id. refresh_hint); // display time timetextview = (textview) refreshview. findviewbyid (R. id. refresh_time); layoutparams Lp = new linearlayout. layoutparams (layoutparams. fill_parent,-refreshtargettop); LP. topmargin = refreshtargettop; LP. gravity = gravity. center; addview (refreshview, LP); downtextstring = mcontext. getresources (). getstring (R. st Ring. refresh_down_text); releasetextstring = mcontext. getresources (). getstring (R. string. refresh_release_text);}/*** refresh * @ Param time */private void setrefreshtext (string time) {// todo auto-generated method stub // timetextview. settext (time) ;}@ overridepublic Boolean ontouchevent (motionevent event) {int y = (INT) event. getrawy (); Switch (event. getaction () {Case motionevent. action_down: // record y coordinate lasty = Y; break; Case motionevent. action_move: log. I (TAG, "action_move"); // y Moving Coordinate int M = Y-lasty; If (M <6) & (M>-1 )) | (! Isdragging) {domovement (m);} // record the Y coordinate at the moment this. lasty = y; break; Case motionevent. action_up: log. I (TAG, "action_up"); fling (); break;} return true;}/*** up event processing */private void fling () {// todo auto-generated method stublinearlayout. layoutparams Lp = (layoutparams) refreshview. getlayoutparams (); log. I (TAG, "fling ()" + LP. topmargin); If (LP. topmargin> 0) {// pull the refresh event refresh () ;}else {returninitstate () ;}} private Void returninitstate () {// todo auto-generated method stub linearlayout. layoutparams Lp = (linearlayout. layoutparams) This. refreshview. getlayoutparams (); int I = LP. topmargin; scroller. startscroll (0, I, 0, refreshtargettop); invalidate ();} private void refresh () {// todo auto-generated method stub linearlayout. layoutparams Lp = (linearlayout. layoutparams) This. refreshview. getlayoutparams (); int I = L P. topmargin; refreshindicatorview. setvisibility (view. gone); Bar. setvisibility (view. visible); timetextview. setvisibility (view. gone); downtextview. setvisibility (view. gone); scroller. startscroll (0, I, 0, 0-i); invalidate (); If (refreshlistener! = NULL) {refreshlistener. onrefresh (this); isrefreshing = true ;}/ *****/@ overridepublic void computescroll () {// todo auto-generated method stubif (scroller. computescroloffset () {int I = This. scroller. getcurry (); linearlayout. layoutparams Lp = (linearlayout. layoutparams) This. refreshview. getlayoutparams (); int K = math. max (I, refreshtargettop); LP. topmargin = K; this. refreshview. setlayoutparams (LP ); This. refreshview. invalidate (); invalidate () ;}}/*** pull-down move event handling * @ Param Movey */private void domovement (INT Movey) {// todo auto-generated method stublinearlayout. layoutparams Lp = (layoutparams) refreshview. getlayoutparams (); If (Movey> 0) {// get the top margin float F1 = LP of the view. topmargin; float F2 = Movey * 0.3f; int I = (INT) (F1 + F2); // modify the top margin LP. topmargin = I; // refreshview after modification. setlayoutparams (LP); refreshview. inva Lidate (); invalidate ();} timetextview. setvisibility (view. Visible); If (refreshtime! = NULL) {setrefreshtime (refreshtime);} downtextview. setvisibility (view. visible); refreshindicatorview. setvisibility (view. visible); Bar. setvisibility (view. gone); If (LP. topmargin> 0) {downtextview. settext (R. string. refresh_release_text); refreshindicatorview. setimageresource (R. drawable. refresh_arrow_up);} else {downtextview. settext (R. string. refresh_down_text); refreshindicatorview. setimageresource (R. drawable. refresh_arrow_down);} public void setrefreshenabled (Boolean B) {This. isrefreshenabled = B;} public void setrefreshlistener (refreshlistener listener) {This. refreshlistener = listener;}/*** refresh time * @ Param refreshtime2 */private void setrefreshtime (long time) {// todo auto-generated method stub}/*** end refresh event */Public void finishrefresh () {log. I (TAG, "executed ==== finishrefresh"); linearlayout. layoutparams Lp = (linearlayout. layoutparams) This. refreshview. getlayoutparams (); int I = LP. topmargin; refreshindicatorview. setvisibility (view. visible); timetextview. setvisibility (view. visible); scroller. startscroll (0, I, 0, refreshtargettop); invalidate (); isrefreshing = false;}/* This method is generally used with ontouchevent * (non-javadoc) * @ see android. view. viewgroup # onintercepttouchevent (Android. view. motionevent) */@ overridepublic Boolean onintercepttouchevent (motionevent e) {// todo auto-generated method stubint action = E. getaction (); int y = (INT) E. getrawy (); Switch (Action) {Case motionevent. action_down: lasty = y; break; Case motionevent. action_move: // y movement coordinate int M = Y-lasty; // record the Y coordinate at the moment this. lasty = y; If (M> 6 & canscroll () {return true;} break; Case motionevent. action_up: break; Case motionevent. action_cancel: break;} return false;} private Boolean canscroll () {// todo auto-generated method stubview childview; If (getchildcount ()> 1) {childview = This. getchildat (1); If (childview instanceof listview) {int Top = (listview) childview ). getchildat (0 ). gettop (); int pad = (listview) childview ). getlistpaddingtop (); If (math. ABS (top-pad) <3 & (listview) childview ). getfirstvisibleposition () = 0) {return true;} else {return false;} else if (childview instanceof scrollview) {If (scrollview) childview ). getscrolly () = 0) {return true;} else {return false ;}} return false ;} /*** refresh listener interface ** @ author Nono **/public interface refreshlistener {public void onrefresh (refreshableview view );}}

This control is customized to implement a linear layout. It contains the first child control and refreshes the display view.

Because there are a lot of examples of listview pull-down refresh on the internet, my friend also did this last time. After talking about it for a week, I found a problem. There are too few entries in the listview, the refreshed view is displayed.

I have not read the code, and I have no idea what the situation is.

A little bit of tips are used for self-defining. That is, I set the topmargin of the refresh View to the negative value of the view height, so that it is hidden.

The preceding view display bug caused by too few entries will be fixed.

@ Overridepublic Boolean ontouchevent (motionevent event) {int y = (INT) event. getrawy (); Switch (event. getaction () {Case motionevent. action_down: // record y coordinate lasty = y; break; Case motionevent. action_move: log. I (TAG, "action_move"); // y Moving Coordinate int M = Y-lasty; If (M <6) & (M>-1 )) | (! Isdragging) {domovement (m);} // record the Y coordinate at the moment this. lasty = y; break; Case motionevent. action_up: log. I (TAG, "action_up"); fling (); break;} return true;}/* This method is generally used with ontouchevent * (non-javadoc) * @ see android. view. viewgroup # onintercepttouchevent (Android. view. motionevent) */@ overridepublic Boolean onintercepttouchevent (motionevent e) {// todo auto-generated method stubint action = E. getaction (); int y = (INT) E. getrawy (); Switch (Action) {Case motionevent. action_down: lasty = y; break; Case motionevent. action_move: // y movement coordinate int M = Y-lasty; // record the Y coordinate at the moment this. lasty = y; If (M> 6 & canscroll () {return true;} break; Case motionevent. action_up: break; Case motionevent. action_cancel: break;} return false ;}

Control usage:

<com.xxx.xxxx.view.RefreshableView android:orientation="vertical" android:id="@+id/refresh_root" android:layout_width="fill_parent" android:layout_height="wrap_content"  xmlns:android="http://schemas.android.com/apk/res/android" ><ListView android:id="@+id/def_list" android:layout_width="fill_parent"android:scrollbars="none"  android:fadingEdge="none"android:layout_height="wrap_content" android:scrollingCache="false"></ListView></com.xxxx.xxxxx.view.RefreshableView>

That is, my listview is added with the second sub-view of the control. Now I have another problem: how can I tell whether the refreshableview pull-down refresh operation or the listview pull-down operation is performed when I perform a drop-down operation on the interface. This problem was quite tragic at the beginning, that is, when there is a lot of data in my listview, then my gestures slide over the network, and the operation will not conflict at the moment, because the listener for refreshing the view listener's decline event monitors; then, the listview slides to the bottom. If I want to go back to the top of the listview, I have to perform the slide operation. Then, the operation is in conflict with the drop-down refresh listener in the refresh view. Later, we found two functions in the View: subcontrols intercept event functions. Specifically, the click screen is used. The touch event is first captured by onintercepttouchevent, and the Child view is processed first. Then, based on true and false, the Child view determines whether to intercept the event and submit it to the parent view for processing. In this case, we can pre-process onintercepttouchevent to determine that listview is at the bottom of the Buddha and can be degraded to determine that it is Buddha's sub-view to intercept and process the touch event. The specific judgment depends on canscroll (). Considering that scrollview is similar to listview, it is also processed. Therefore, this control supports listview and scrollview. The implementation code is basically the same as above, and there may be many internal bugs, but I have not found the implementation on the application for the moment. Finally, I would like to thank the online refresh code demo, Sina Weibo, and Netease applications for refreshing the control code.

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.