Android easily implements pull-down refresh of imitation QQ space, and android easily implements

Source: Internet
Author: User
Tags control label gety

Android easily implements pull-down refresh of imitation QQ space, and android easily implements

(This article describes the process of implementing the dynamic effect of list drop-down refresh in Android. The source code is included at the end of this Article .)

After reading this article, you can learn:
1. Implementation principle of pull-down refresh

2. Customize the Android control and override its ListView

3. ScrollListener

4. Use of Adapter


Let's take a look:




Next we will implement the above results step by step.


1. ListViewItem

Take a look at this step:



First, we need to implement a ListView with a pull-down refresh effect. Therefore, we chose to override the native control ListView. You only need to write a class to inherit it. First, no specific implementation is added.

RefreshListView. java:

public class RefreshListView extends ListView {public RefreshListView(Context context) {super(context);// TODO Auto-generated constructor stub}public RefreshListView(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}public RefreshListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stub}}

To implement the ListViewItem, You need to define the layout of the Item by yourself. This can be used without limit. Here I will just take the image and text for a simple implementation:

Listview_item.xml:

<?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"    android:gravity="center_vertical"    android:orientation="horizontal" >    <ImageView        android:id="@+id/image"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="10dp" />    <TextView        android:id="@+id/text"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="10dp"        android:textSize="25sp" /></LinearLayout>

In this layout, I only put one Image and one Text. You can define it more complex.

Then we need to note that, since we have defined the ListView ourselves, the layout of our main interface should also be modified in response:

Activity_main.xml:

<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.example.mylistviewrefresh.RefreshListView        android:id="@+id/listview"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:cacheColorHint="#00000000"        android:dividerHeight="5dip" /></RelativeLayout>
We can see at a glance that we modified its control label and changed it to the full path of the class we defined.

At last, MainActivity. java is the main character. I have commented out some codes in detail. Note the use of the adapter.

Public class MainActivity extends Activity {private RefreshListView listView; private SimpleAdapter simple_adapter; private List <Map <String, Object> list; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); listView = (RefreshListView) findViewById (R. id. listview); iniData (); // initialize the data. We add 20 items to it. // set SimpleAdapter listener /** * Meanings of the five parameters of SimpleAdapter: * first: context * Second: data used for display, list of map * Third: Layout of Item, that is, the custom file * Fourth: closely connected with the second parameter, and fifth, is the key value * fifth in map: we can see that it is an array of id (int type). Where does this array come from? It is defined in the layout file by ourselves. If you forget it, you can go back and look at it. * these parameters are independent and may not be known, but I think it's easy to get together. */Simple_adapter = new SimpleAdapter (MainActivity. this, list, R. layout. listview_item, new String [] {"image", "text"}, new int [] {R. id. image, R. id. text}); // sets the adapter listView. setAdapter (simple_adapter);} // initialize SimpleAdapter dataset private List <Map <String, Object> iniData () {list = new ArrayList <Map <String, Object> (); for (int I = 0; I <20; I ++) {Map <String, Object> map = new HashMap <String, Object> (); // explanation The data here, the key corresponds to the third parameter of SimpleAdapter, must contain them. The value corresponds to the fifth parameter, which is the image and text map. put ("text", I); map. put ("image", R. drawable. ic_launcher); list. add (map) ;}return list ;}@ Overridepublic boolean onCreateOptionsMenu (Menu menu) {// Inflate the menu; this adds items to the action bar if it is present. getMenuInflater (). inflate (R. menu. main, menu); return true ;}}

In this step, we should be able to implement the listview of images and text. Let's continue watching it.


2. Add hidden Headers

Here we want to refresh it in the pull-down mode.ImplementationNow:

First, the pull-down refresh we usually use is to show some previously hidden controls on the top of the screen after the drop-down, such as the drop-down arrow and progress bar.

Can we directly set them to invisible? Obviously, this is not acceptable. Because of the display of these spaces, there is a gradient process, not just click it.

So we should do this:

Add a hidden layout and place it above the screen. Display the Response Control Based on the drop-down range.

In this step, we need to add a hidden layout. how to adjust the display status of the Header in real time based on the drop-down status is described below.


We can customize a new layout for the header to be hidden. header. xml:

<? 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 = "wrap_content" android: orientation = "vertical"> <RelativeLayout android: layout_width = "match_parent" android: layout_height = "wrap_content" android: paddingBottom = "10dip" android: paddingTop = "10dip"> <LinearLayout android: id = "@ + id/layout" android: layout_width = "wrap_content" Android: layout_height = "wrap_content" android: layout_centerInParent = "true" android: gravity = "center" android: orientation = "vertical"> <TextView android: id = "@ + id/tip" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "pull-down list to refresh! "/> <TextView android: id =" @ + id/lastupdate_time "android: layout_width =" wrap_content "android: layout_height =" wrap_content "/> </LinearLayout> <ImageView android: id = "@ + id/arrow" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_toLeftOf = "@ id/layout" android: layout_marginRight = "20dip" android: src = "@ drawable/pull_to_refresh_arrow"/> <ProgressBar android: id = "@ + id/p Rogress "style = "? Android: attr/progressBarStyleSmall "android: layout_width =" wrap_content "android: layout_height =" wrap_content "android: layout =" @ id/layout "android: layout_marginRight =" 20dip "android: visibility = "gone"/> </RelativeLayout> </LinearLayout>


This layout contains the prompt "pull-down refresh", the latest update time, and the drop-down arrow pictures (which are already in the drawable folder. You can find an image and put it in it, name it pull_to_refresh_arrow.phg), a progressbar that is displayed only when it is updated (hidden now ).

To add this layout to our defined List, we need to rewrite the previously customized RefreshLIstview control:

Public class RefreshListView extends ListView {View header; // top layout file; int headerHeight; // height of the top layout file; public RefreshListView (Context context) {super (context ); // TODO Auto-generated constructor stubinitView (context);} public RefreshListView (Context context, AttributeSet attrs) {super (context, attrs ); // TODO Auto-generated constructor stubinitView (context);} public RefreshListView (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle ); // TODO Auto-generated constructor stubinitView (context);}/*** initialize the interface and add the top layout file to listview */private void initView (Context context) {LayoutInflater inflater = LayoutInflater. from (context); header = inflater. inflate (R. layout. header, null); measureView (header); headerHeight = header. getMeasuredHeight (); Log. I ("tag", "headerHeight =" + headerHeight); // topPadding (-headerHeight); // This line is commented out by me. If you remove the comment, this is displayed. addHeaderView (header);}/*** notification parent layout, occupied width and height; */private void measureView (View view) {ViewGroup. layoutParams p = view. getLayoutParams (); if (p = null) {p = new ViewGroup. layoutParams (ViewGroup. layoutParams. MATCH_PARENT, ViewGroup. layoutParams. WRAP_CONTENT);} int width = ViewGroup. getChildMeasureSpec (0, 0, p. width); int height; int tempHeight = p. height; if (tempHeight> 0) {height = MeasureSpec. makeMeasureSpec (tempHeight, MeasureSpec. EXACTLY);} else {height = MeasureSpec. makeMeasureSpec (0, MeasureSpec. UNSPECIFIED);} view. measure (width, height);}/*** sets the top margin of the header layout; */private void topPadding (int topPadding) {header. setPadding (header. getPaddingLeft (), topPadding, header. getPaddingRight (), header. getPaddingBottom (); header. invalidate ();}}

The main implementation is to add the new header and hide it. Now I have commented out the line of code that hides the header. Let's look at the effect:


If the comment is removed, the header is hidden.


3. Add a rolling listener to adjust the display status of the Header in real time and add data after refreshing

Ideas:

Add a screen touch listener and a screen scroll listener.

Touch listeningEspecially important:

Recording at touchY value of the touch CoordinateThat is, startY, and then listen to the current Y value during the moving process,Determine the current moving distance based on the interpolation between the two and compare it with some critical values..

After comparisonReturns the current status.: Displays the drop-down status, release status, and refresh status. Refresh the display of the header layout based on the current status.

Scroll listenerThe function is to determine whether the current is the top of the list (by determining whether the position of the first item currently visible is 0), and then determine the screen scroll status.


In addition, an interface is defined in the Custom Listview class, which is implemented in mainactivity to refresh data. We used Handler to delay the refresh for two seconds to clearly see the refresh effect.

The modified MainActivity and ListView:

ListView: (there are a lot of comments in it, which should be easy to understand)

Public class RefreshListView extends ListView implements OnScrollListener {View header; // layout file on the top; int headerHeight; // layout file height on the top; int firstVisibleItem; // The Position of the first visible item; int scrollState; // The current rolling status of listview; boolean isRemark; // mark, which is currently at the top of listview; int startY; // The Y value when the press is down; int state; // current state; final int NONE = 0; // normal state; final int PULL = 1; // The drop-down status is displayed; final int RELEASE = 2; // The RELEASE status is displayed; final int REFRESHING = 3; // click it New status; IRefreshListener iRefreshListener; // interface for refreshing data public RefreshListView (Context context) {super (context); // TODO Auto-generated constructor stubinitView (context );} public RefreshListView (Context context, AttributeSet attrs) {super (context, attrs); // TODO Auto-generated constructor stubinitView (context);} public RefreshListView (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, d EfStyle); // TODO Auto-generated constructor stubinitView (context);}/*** initialization interface, add the layout file on the top to listview ** @ param context */private void initView (Context context) {LayoutInflater inflater = LayoutInflater. from (context); header = inflater. inflate (R. layout. header, null); measureView (header); headerHeight = header. getMeasuredHeight (); Log. I ("tag", "headerHeight =" + headerHeight); topPadding (-headerHeight); th Is. addHeaderView (header); this. setOnScrollListener (this);}/*** notification parent layout, occupied width and height; ** @ param view */private void measureView (View view) {ViewGroup. layoutParams p = view. getLayoutParams (); if (p = null) {p = new ViewGroup. layoutParams (ViewGroup. layoutParams. MATCH_PARENT, ViewGroup. layoutParams. WRAP_CONTENT);} int width = ViewGroup. getChildMeasureSpec (0, 0, p. width); int height; int tempHeight = p. height; if (TempHeight> 0) {height = MeasureSpec. makeMeasureSpec (tempHeight, MeasureSpec. EXACTLY);} else {height = MeasureSpec. makeMeasureSpec (0, MeasureSpec. UNSPECIFIED);} view. measure (width, height);}/*** sets the header layout top margin; ** @ param topPadding */private void topPadding (int topPadding) {header. setPadding (header. getPaddingLeft (), topPadding, header. getPaddingRight (), header. getPaddingBottom (); header. invalida Te () ;}@ Overridepublic void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {// TODO Auto-generated method stubthis. firstVisibleItem = firstVisibleItem;} @ Overridepublic void onScrollStateChanged (AbsListView view, int scrollState) {// TODO Auto-generated method stubthis. scrollState = scrollState;}/*** monitors the screen touch. * first checks whether the current status is at the top. If it is at the top, record the Y value you are about to slide * and then during the slide process (the ACTION_MOVE is listened ), constantly judge whether the current sliding range has reached the level that should be refreshed. * (Based on the relationship between the current Y-previous startY value and the height of our control) * then, when the finger is released, perform operations based on the current status (which we calculated in onmove. * // @ Overridepublic boolean onTouchEvent (MotionEvent ev) {// TODO Auto-generated method stubswitch (ev. getAction () {case MotionEvent. ACTION_DOWN: if (firstVisibleItem = 0) {isRemark = true; startY = (int) ev. getY ();} break; case MotionEvent. ACTION_MOVE: onMove (ev); break; case MotionEvent. ACTION_UP: if (state = RELEASE) {// The system prompts you to RELEASE the refresh status. Once released, the system enters the refreshing status. At this time, data can be loaded! State = REFRESHING; // load the latest data; refreshViewByState (); iRefreshListener. onRefresh ();} else if (state = PULL) {// a drop-down status prompt is displayed. if the drop-down status is set, restore everything and do nothing state = NONE; isRemark = false; refreshViewByState ();} break;} return super. onTouchEvent (ev);}/*** determines the operation of the moving process: * if it is not the top, no operation is required * Otherwise, the current Y value is obtained, compare with the starting Y value. * Determine the height of the drop-down list and determine the critical values we have defined (you can define the critical values yourself) ** @ param ev */private void onMove (MotionEvent ev) {if (! IsRemark) {return;} int tempY = (int) ev. getY (); int space = tempY-startY; int topPadding = space-headerHeight; switch (state) {case NONE: if (space> 0) {state = PULL; // pulling down refreshViewByState ();} break; case PULL: topPadding (topPadding); // if the height is greater than a certain value and the rolling status is rolling, the refresh state is released. if (space> headerHeight + 30 & scrollState = SCROLL_STATE_TOUCH_SCROLL) {state = RELEASE; refreshViewByState ();} break; case RELEA SE: topPadding (topPadding); // when you are prompted to release the refresh, if you drag it up, if the distance is less than a certain height, you are prompted to refresh the if (space 

MainActivity: (added interface callback, that is, the method for adding data to main is called in listview)

Public class MainActivity extends Activity implements IRefreshListener {private RefreshListView listView; private SimpleAdapter simple_adapter; private List <Map <String, Object> list; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); listView = (RefreshListView) findViewById (R. id. listview); iniData (); // initialize the data. We add 20 pieces of I Tem // set the meaning of the five parameters of SimpleAdapter listener/*** SimpleAdapter: * first: context * Second: data used for display, list of map * Third: item layout, that is, the custom file * Fourth: closely related to the second parameter, and fifth, is the key value * fifth in map: we can see that it is an array of id (int type). Where does this array come from? It is defined in the layout file by ourselves. If you forget it, you can go back and look at it. * these parameters are independent and may not be known, but I think it's easy to get together. */Simple_adapter = new SimpleAdapter (MainActivity. this, list, R. layout. listview_item, new String [] {"image", "text"}, new int [] {R. id. image, R. id. text}); // sets the adapter listView. setAdapter (simple_adapter); // sets the data update interface listView. setInterface (this) ;}// initialize SimpleAdapter dataset private List <Map <String, Object> iniData () {list = new ArrayList <Map <String, Object> (); for (int I = 0; I <20; I ++) {Map <String, Object> Map = new HashMap <String, Object> (); // explain the data here. The key corresponds to the third parameter of SimpleAdapter and must contain them. The value corresponds to the fifth parameter, which is the image and text map. put ("text", I); map. put ("image", R. drawable. ic_launcher); list. add (map) ;}return list ;}@ Overridepublic boolean onCreateOptionsMenu (Menu menu) {// Inflate the menu; this adds items to the action bar if it is present. getMenuInflater (). inflate (R. menu. main, menu); return true;}/*** interface callback. You can call this method in RefreshListView to add data. * // @ Overridepublic void onRefresh () {// Handler handler = new Handler (); handler automatically generated by TODO. postDelayed (new Runnable () {@ Overridepublic void run () {// TODO Auto-generated method stubMap <String, Object> map = new HashMap <String, Object> (); map. put ("text", "scroll to add"); map. put ("image", R. drawable. ic_launcher); list. add (0, map); listView. setAdapter (simple_adapter); simple_adapter.notifyDataSetChanged (); listView. refreshComplete () ;}, 2000 );}}

Here, we have implemented the beginning of the article.


==========================================================

Written below:

The source code has been uploaded to my Github or downloaded from the online storage.

For any questions, please leave a message!


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.