[Android Notes] use and implementation of the pull-down and refresh components and Android notes drop-down Components
If you need to implement pull-down refresh in a project, you can choose from the following options:1. Use the open-source library Android-pullToRefresh.2. Use SwipeRefreshLayout provided by the support. v4 package.3. Implement one by yourself.
The following is a brief introduction: Note: The listView pull-down refresh is used as an example.Solution 1: use the open-source library Android-pullToRefresh1. download Android-PullToRefresh open source Library (https://github.com/chrisbanes/Android-PullToRefresh) 2. import the library project to eclipse. create a new project and reference the library in properties> android. write code
This library provides PullToRefreshListView. We use it to replace ListView, which is consistent with ListView in usage. However, it provides an interface for listening for pull-down update. We can use setOnRefreshListener to register the listener and then asynchronously update the data in the onRefresh callback method. After the update is complete, we need to call the onRefreshComplete method to complete the update. Example: page layout:
<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="com.example.flushlistview.MainActivity" > <com.handmark.pulltorefresh.library.PullToRefreshListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="#19000000" android:dividerHeight="4dp" > </com.handmark.pulltorefresh.library.PullToRefreshListView></RelativeLayout>
ListView item layout:
<?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:orientation="vertical" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#000" android:textSize="20sp" /></LinearLayout>
Interface logic:
Package com. example. flushlistview; import java. text. simpleDateFormat; import java. util. arrayList; import java. util. date; import java. util. list; import java. util. locale; import android. app. activity; import android. OS. asyncTask; import android. OS. bundle; import android. widget. arrayAdapter; import android. widget. listView; import com. handmark. pulltorefresh. library. pullToRefreshBase; import com. handmark. pulltorefresh. library. pullToRefreshBase. onRefreshListener; import com. handmark. pulltorefresh. library. pullToRefreshListView;/*** @ author Rowandjj ** use the pull-to-refresh library to perform the pull-down refresh operation */public class MainActivity extends Activity {private PullToRefreshListView lv; private ArrayAdapter <String> adapter; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); lv = (PullToRefreshListView) findViewById (R. id. lv); List <String> list = new ArrayList <String> (); list. add ("Zhang San"); list. add ("Li Si"); list. add ("Wang Wu"); list. add ("Zhao six"); list. add ("ah"); list. add ("Haha"); list. add (""); list. add (""); adapter = new ArrayAdapter <String> (this, R. layout. item, R. id. TV, list); lv. setAdapter (adapter); // implements the refresh interface lv. setOnRefreshListener (new OnRefreshListener <ListView> () {@ Overridepublic void onRefresh (PullToRefreshBase <ListView> refreshView) {Date date = new Date (System. currentTimeMillis (); SimpleDateFormat format = new SimpleDateFormat ("MM: dd, yyyy, hh, mm: ss seconds", Locale. CHINA); String updateTime = format. format (date); refreshView. getLoadingLayoutProxy (). setLastUpdatedLabel (updateTime); // asynchronously refresh new updatetask(cmd.exe cute () ;});} private class UpdateTask extends AsyncTask <Void, Void, list <String >>{@ Overrideprotected List <String> doInBackground (Void... params) {try {Thread. sleep (2000);} catch (InterruptedException e) {e. printStackTrace () ;}list <String> newData = new ArrayList <String> (); newData. add ("new data 1"); newData. add ("new data 2"); newData. add ("new data 3"); return newData ;}@ Overrideprotected void onPostExecute (List <String> result) {adapter. addAll (result); // The lv is refreshed. onRefreshComplete ();}}}
Effect:
Solution 2: Use SwipeRefreshLayout provided by the support. v4 packageSwipeRefreshLayout is a class provided by the support. v4 package. It can implement pull-down refresh with the Material Design effect. The usage is also very simple. You only need to place the ListView/RecyclerView or other views in this layout, then call the setOnRefreshListener to register the data update interface, and process data update events in the onRefresh method. After the data is updated, call setRefreshing and set the parameter to false. Note: 1. SwipeRefreshLayout can enclose only one subview. 2. If your support. v4 package does not have this class, you need to update it.
Example: page layout:
<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="com.example.swiperefreshlayoutdemo.MainActivity" > <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/activity_main_swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="wrap_content" > <ListView android:id="@+id/activity_main_listview" android:layout_width="match_parent" android:layout_height="match_parent" > </ListView> </android.support.v4.widget.SwipeRefreshLayout></RelativeLayout>
Item layout:
<?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" > <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="40dip" android:textColor="#000" android:gravity="center_vertical" android:textSize="18sp" /></LinearLayout>
Page logic:
Package com. example. swiperefreshlayoutdemo; import java. util. arrayList; import java. util. list; import android. app. activity; import android. OS. asyncTask; import android. OS. bundle; import android. support. v4.widget. swipeRefreshLayout; import android. support. v4.widget. swipeRefreshLayout. onRefreshListener; import android. widget. arrayAdapter; import android. widget. listView; public class MainActivity extends Activity {private ListView mListView; private SwipeRefreshLayout mRefreshLayout; private ArrayAdapter <String> mAdapter; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); mListView = (ListView) findViewById (R. id. activity_main_listview); mRefreshLayout = (SwipeRefreshLayout) findViewById (R. id. activity_main_swipe_refresh_layout); List <String> data = new ArrayList <String> (); for (int I = 0; I <15; I ++) {data. add ("this is data" + I);} mAdapter = new ArrayAdapter <String> (this, R. layout. item, R. id. TV, data); mListView. setAdapter (mAdapter); mRefreshLayout. setOnRefreshListener (new OnRefreshListener () {@ Overridepublic void onRefresh () {new updatetask(.exe cute () ;}});} private class UpdateTask extends AsyncTask <Void, Void, list <String >>{@ Overrideprotected List <String> doInBackground (Void... params) {try {Thread. sleep (2000);} catch (InterruptedException e) {e. printStackTrace () ;}list <String> newData = new ArrayList <String> (); newData. add ("new data 1"); newData. add ("new data 2"); newData. add ("new data 3"); return newData ;}@ Overrideprotected void onPostExecute (List <String> result) {mAdapter. addAll (result); // notification Data Update completed mRefreshLayout. setRefreshing (false );}}}
Effect:
Solution 3: implement one by yourselfTo achieve a pull-down refresh effect, you must have a clear understanding of android's event distribution and Event Callback mechanisms. Here I directly inherit from the ListView, and then listen to the screen rolling event by implementing the OnScrollListener, because only the ListView slides to the first part to slide and refresh. In addition, I need to override the onTouchEvent method to dynamically update the Layout Based on the finger position. By analyzing the traditional pull-down refresh, We found four statuses: 1. Normal, 2. pull-down refresh, 3. Release refresh, and 4. Refresh.
When you press the finger, first determine whether the first item of the current listView is visible. If not visible, do not process it. Otherwise, write down the current position. When the finger moves, the offset in the vertical direction is calculated, the current status is changed based on the offset, and the layout is updated based on the current status. The layout here refers to the headerView of listView. Of course, this view is hidden by default. We can set its padding to the height of the negative headerview. When the finger is released, the current status is determined. If it is refreshed, the callback interface is called to process the update logic.
First paste the Code:
Package com. example. mypulltorefreshlistview. ui; import java. text. simpleDateFormat; import java. util. date; import java. util. locale; import android. content. context; import android. util. attributeSet; import android. util. log; import android. view. layoutInflater; import android. view. motionEvent; import android. view. view; import android. view. animation. animation; import android. view. animation. animationUtils; import Droid. widget. absListView; import android. widget. absListView. onScrollListener; import android. widget. imageView; import android. widget. listView; import android. widget. progressBar; import android. widget. textView; import com. example. mypulltorefreshlistview. r; public class PullToRefreshListView extends ListView implements OnScrollListener {private static final String TAG = "PullToRefreshListView";/*** top Layout */p Rivate View mHeaderView;/*** header height */private int mHeaderHeight;/*** the current page has slipped to the top */private boolean flag; /*** y coordinate */private int mStartY During Initial Sliding;/*** normal state */public static final int STATE_NORMAL = 0; /*** pull-down refresh status */public static final int STATE_PULL_TO_REFRESH = 1;/*** release refresh status */public static final int STATE_RELEASE_TO_REFRESH = 2; /*** refreshing status */public static final int STATE_REFRESH = 3;/*** current status */Private int mCurrentState; private static final int DEFAULT_LENGTH = 70; private OnRefreshListener mRefreshListener; public listener (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle ); init (context);} public PullToRefreshListView (Context context, AttributeSet attrs) {super (context, attrs); init (context);} public PullToRefreshListView (Context context) {super (co Ntext); init (context);} public void setOnRefreshListener (OnRefreshListener listener) {this. mRefreshListener = listener;}/*** initialization operation * @ param context */private void init (Context context) {// Add headerviewmHeaderView = LayoutInflater. from (context ). inflate (R. layout. header_layout, null); this. addHeaderView (mHeaderView); // sets the rolling listener this. setOnScrollListener (this); // hide the hider by setting the padding // Note: Because the height of the header cannot be obtained at this time, put it in the Mess Post (new HideHeaderAction ();}/*** set the header padding * @ param topPadding */private void setHeaderTopPadding (int topPadding) {if (mHeaderView! = Null) {mHeaderView. setPadding (mHeaderView. getPaddingLeft (), topPadding, mHeaderView. getPaddingRight (), mHeaderView. getPaddingBottom (); }}@ Overridepublic void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {if (firstVisibleItem = 0) flag = true; elseflag = false ;}@ Overridepublic void onScrollStateChanged (AbsListView view, int scrollState) {}@ Overridepublic boolea N onTouchEvent (MotionEvent ev) {int action = ev. getAction (); switch (action) {case MotionEvent. ACTION_DOWN: if (flag) {mStartY = (int) ev. getY ();} break; case MotionEvent. ACTION_MOVE: Required mmove (ev); break; case MotionEvent. ACTION_UP: if (mCurrentState = empty) {mCurrentState = STATE_REFRESH; updateUIByState (); // TODO load new data if (mRefreshListener = null) {throw new RuntimeException ("you must call SetOnRefreshListener before... ");} else {mRefreshListener. onRefresh (this) ;}} else if (mCurrentState = STATE_PULL_TO_REFRESH) {mCurrentState = STATE_NORMAL; flag = false; updateUIByState ();} break;} super return. onTouchEvent (ev);} private void updateUIByState () {TextView tip = (TextView) findViewById (R. id. tip); ImageView arrow = (ImageView) findViewById (R. id. arrow); ProgressBar progressBar = (ProgressBar) fin DViewById (R. id. progress); Animation anim1 = AnimationUtils. loadAnimation (getContext (), R. anim. rotate_1); Animation anim2 = AnimationUtils. loadAnimation (getContext (), R. anim. rotate_2); switch (mCurrentState) {case STATE_NORMAL: setHeaderTopPadding (-mHeaderHeight); break; case STATE_PULL_TO_REFRESH: arrow. clearAnimation (); arrow. setAnimation (anim1); arrow. setVisibility (View. VISIBLE); progressBar. setVisibility (Vi Ew. GONE); tip. setText ("pull down to refresh... "); break; case STATE_RELEASE_TO_REFRESH: arrow. clearAnimation (); arrow. setAnimation (anim2); arrow. setVisibility (View. VISIBLE); progressBar. setVisibility (View. GONE); tip. setText ("release to refresh... "); break; case STATE_REFRESH: arrow. clearAnimation (); setHeaderTopPadding (mHeaderHeight); arrow. setVisibility (View. GONE); progressBar. setVisibility (View. VISIBLE); tip. setText ("refreshing... "); break; de Fault: break;} private void merge mmove (MotionEvent ev) {if (! Flag) {return;} int currY = (int) ev. getY (); int deltaY = currY-mStartY; if (deltaY> mHeaderHeight + DEFAULT_LENGTH) deltaY = mHeaderHeight + DEFAULT_LENGTH; switch (mCurrentState) {case STATE_NORMAL: if (deltaY> 0) {mCurrentState = signature;} break; case when: setHeaderTopPadding (deltaY-mHeaderHeight); updateUIByState (); if (deltaY> = mHeaderHeight + DEFAULT_LENGTH) {mCurrentState = signature ;} else if (deltaY <= 0) {mCurrentState = STATE_NORMAL;} break; case when: // else (deltaY-mHeaderHeight); updateUIByState (); if (deltaY <mHeaderHeight + DEFAULT_LENGTH) {mCurrentState = STATE_PULL_TO_REFRESH;} else if (deltaY <= 0) {mCurrentState = STATE_NORMAL;} break;}/*** call */public void refreshComplete () when the update is complete () {TextView lastUpdateTime = (TextView) findViewById (R. id. last_update_time); SimpleDateFormat format = new SimpleDateFormat ("MM-dd hh: mm", Locale. CHINA); String updateTime = format. format (new Date (System. currentTimeMillis (); lastUpdateTime. setText ("updated on" + updateTime); mCurrentState = STATE_NORMAL; updateUIByState ();} public interface OnRefreshListener {public void onRefresh (PullToRefreshListView listView );} private class HideHeaderAction implements Runnable {@ Overridepublic void run () {// get the height of the header mHeaderHeight = mHeaderView. getMeasuredHeight (); // view cannot obtain its width and height Log before being rendered. d (TAG, "Headerheight:" + mHeaderHeight); // you can set the header padding to hide headersetHeaderTopPadding (-mHeaderHeight );}}}
Similar to the above, you also need to add a listener and then process the callback method. After the data is updated, refreshComplete is called. Of course, this is just a simple demo, and the effect may not be very good, for reference only ~