1. 程式人生 > >自定義ViewGroup繼承FrameLayout 實現下拉重新整理功能

自定義ViewGroup繼承FrameLayout 實現下拉重新整理功能

程式碼不多,註釋也不多,因為比較簡單

效果圖


貼程式碼

activity_refresh_head.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="50dp"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp" >

        <TextView
            android:id="@+id/refresh_head_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="TextView" />

        

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:orientation="horizontal" >
            
            <RelativeLayout
	            android:layout_width="0dp"
	            android:layout_height="match_parent"
	            android:layout_weight="0.5" >
            
                <ImageView
		            android:id="@+id/refresh_head_img"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:layout_centerInParent="true"
		            android:src="@drawable/jiangou" />
                
       	   </RelativeLayout>
       	   
            <View
	            android:layout_width="0dp"
	            android:layout_height="match_parent"
	            android:layout_weight="0.5" >
            
       	   </View>
        </LinearLayout>

    </RelativeLayout>

</LinearLayout>

activity_main.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:orientation="vertical" >
    
	<com.test_myrefresh_list.views.MyRefreshListView 
	    android:id="@+id/refreshview"
	    android:layout_width="match_parent"
	    android:layout_height="match_parent"
	    android:orientation="vertical">
<!--  
		<ListView
		    android:id="@+id/refreshListView"
		    android:layout_width="match_parent"
		    android:layout_height="match_parent"
		    android:background="@android:color/black" >
		</ListView>
-->	    
	</com.test_myrefresh_list.views.MyRefreshListView>
</LinearLayout>


activity_list_item.xml     (listView 的item佈局)

<?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/textView1"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="TextView" />

</LinearLayout>


MyRefreshListView.java       (自定義的ViewGroup佈局)

package com.test_myrefresh_list.views;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.example.test_myrefresh_list.R;
import com.nineoldandroids.view.ViewHelper;

public class MyRefreshListView extends FrameLayout implements OnTouchListener{
	private View view_head;
	private ImageView head_img;
	private TextView head_text;
	
	//重新整理的頭部高度
	private int headView_height = -1;
	//重新整理的頭部當前拉伸高度
	private int now_trans_height;
	
	//主體listview
	private ListView list;
	private BaseAdapter adapter;
	
	//儲存當前的y座標
	private float y;
	//儲存按下時的y座標
	private float down_y;
	//是否可以重新整理
	private boolean canRefresh = false;
	//是否正在重新整理
	private boolean isRefresh = false;
	//是否正在滑動重新整理欄
	private boolean isSlide = false;
	
	private final int MODE_DISS = 0;
	private final int MODE_REFRESH = 1;
	
	private final String noRefreshText = "   下拉重新整理...";
	private final String canRefreshText = "   釋放可重新整理...";
	private final String nowRefreshText = "   正在重新整理...";
	//重新整理時的回撥事件
	private OnRefreshing refreshCallback;
	
	private Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			float du = (float) msg.obj;
			ViewHelper.setRotation(head_img, du);
		};
	};
	
	public MyRefreshListView(Context context) {
		super(context);
		init(context);
		// TODO Auto-generated constructor stub
	}

	public MyRefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
		// TODO Auto-generated constructor stub
	}

	public MyRefreshListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
		// TODO Auto-generated constructor stub
	}
	
	//初始化
	private void init(Context context){
		view_head = inflate(context, R.layout.activity_refresh_head, null);
		head_img = (ImageView) view_head.findViewById(R.id.refresh_head_img);
		head_text = (TextView) view_head.findViewById(R.id.refresh_head_text);
		head_img.setImageResource(R.drawable.jiangou);
		head_text.setText(noRefreshText);

		list = new ListView(context);
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
		list.setLayoutParams(params);
		list.setOnTouchListener(this);
		
		this.addView(view_head,0);
		this.addView(list,1);
	}

	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		//設定頭部高度,只需要設定一次就可以
		if(headView_height == -1){
			view_head.measure(widthMeasureSpec, 0);
			headView_height = view_head.getMeasuredHeight() ;
			now_trans_height = -headView_height;
			ViewHelper.setTranslationY(view_head, now_trans_height);
		}
	}
	
	
	
	//listView 設定OnTouch
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		switch(event.getAction()){
			case MotionEvent.ACTION_DOWN :{
				y = event.getRawY();
				down_y = event.getRawY();
				break;
			}
			case MotionEvent.ACTION_MOVE :{
				//如果是在滑動或者list中的第一項是第一個item,就表示可以滑動
				if(isSlide ||isListFrist() ){
					return move(event);
				}
				else{
					y = event.getRawY();
				}
				break;
			}
			case MotionEvent.ACTION_UP :{
				up();
				//只有touch的起點在落點附近正負10畫素的位置內時,才有返回OnItemClick事件 
				float uy = event.getRawY();
				if(uy > down_y + 10 || uy < down_y - 10){
					return true;
				}
				break;
			}
		}
		return false;
	}
	
	private boolean move(MotionEvent event){
		float now_y = event.getRawY();
		float cha = now_y - y;
		//如果已經不在滑動且 手勢為向上,則將此次事件返回給list
		if(!isSlide && cha < 0){
			return false;
		}
		now_trans_height += cha;
		//頭部已經滑到最頂部,此時被隱藏,不可滑動
		if(now_trans_height < -headView_height){
			now_trans_height = -headView_height;
			isSlide = false;
		}
		else{
			isSlide = true;
		}
		this.y = now_y;
		//滑動
		ViewHelper.setTranslationY(view_head, now_trans_height);
		ViewHelper.setTranslationY(list, now_trans_height+headView_height);
		//頭部是否已經滑動到可以重新整理的閾值
		if(now_trans_height >= 0  && !canRefresh &&!isRefresh){
			canRefresh = true;
			ViewHelper.setRotation(head_img, 180f);
			head_text.setText(canRefreshText);
		}
		else if(now_trans_height < 0  && canRefresh &&!isRefresh){
			canRefresh = false;
			ViewHelper.setRotation(head_img, 0f);
			head_text.setText(noRefreshText);
		}
		return true;
	}
	
	private void up(){
		if(canRefresh){
			//重新整理
			new MyTask().execute(MODE_REFRESH);
		}
		else{
			//隱藏
			new MyTask().execute(MODE_DISS);
		}
		canRefresh = false;
	}
	
	private boolean isListFrist(){
		int i = list.getFirstVisiblePosition();
		if(i == 0){
			View v = list.getChildAt(0);
			if(v.getTop() == 0){
				return true;
			}
		}
		return false;
	}
	//隱藏
	private void diss(){
		head_img.setImageResource(R.drawable.jiangou);
		head_text.setText(nowRefreshText);
		now_trans_height = -headView_height;
		ViewHelper.setRotation(head_img, 0);
		ViewHelper.setTranslationY(view_head, now_trans_height);
		ViewHelper.setTranslationY(list, 0);
	}
	//展示可重新整理
	private void show_refresh(){
		isRefresh = true;
		head_text.setText(nowRefreshText);
		now_trans_height = 0;
		ViewHelper.setTranslationY(view_head, now_trans_height);
		ViewHelper.setTranslationY(list, headView_height);
		refreshCallback.callback();
		new Thread(refreshing).start();
	}
	//重新整理時的回撥事件
	public void setOnRefreshingCallback(OnRefreshing callback){
		this.refreshCallback = callback;
	}
	
	//重新整理成功時呼叫此方法
	public void refreshOK(){
		isRefresh = false;
		new MyTask().execute(MODE_DISS);
	}
	
	//重新整理時 呼叫此runnable來旋轉圖示
	Runnable refreshing = new Runnable() {
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			float f = 180;
			while(isRefresh){
				Message message = new Message();
				message.obj = f;
				message.what = 0;
				handler.sendMessage(message);
				f += 9;
				try{
					Thread.sleep(50);
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
	};
	
	private class MyTask extends AsyncTask<Integer, Integer, Integer>{

		@Override
		protected Integer doInBackground(Integer... params) {
			// TODO Auto-generated method stub
			int mode = params[0];
			int cha = 0;
			if(mode == MODE_DISS){
				cha = (-headView_height - now_trans_height) / 50;
			}
			else{
				cha = (0 - now_trans_height) / 50;
			}
			int i = 0;
			while(i < 50){
				publishProgress(cha);
				try{
					Thread.sleep(2);
				}catch(Exception e){
					
				}
				i++;
			}
			return mode;
		}
		
		@Override
		protected void onProgressUpdate(Integer... values) {
			// TODO Auto-generated method stub
			now_trans_height += values[0];
			ViewHelper.setTranslationY(view_head, now_trans_height);
			ViewHelper.setTranslationY(list, now_trans_height +headView_height);
		}
		
		@Override
		protected void onPostExecute(Integer result) {
			// TODO Auto-generated method stub
			int mode = result;
			if(mode == MODE_DISS){
				diss();
			}
			else{
				show_refresh();
			}
		}
	}
	
	//
	public void setAdapter(BaseAdapter adapter){
		this.adapter = adapter;
		list.setAdapter(adapter);

	}

	public void setOnItemClickLintener(OnItemClickListener listener){
		list.setOnItemClickListener(listener);
	}
	
	//定義重新整理時呼叫的介面
	public interface OnRefreshing{
		public void callback();
	}
}


MainActivity.java    (主介面)
package com.test_myrefresh_list.views;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.test_myrefresh_list.R;
import com.test_myrefresh_list.views.MyRefreshListView.OnRefreshing;

public class MainActivity extends Activity implements OnItemClickListener{
	private MyRefreshListView refresh;
	private Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			refresh.refreshOK();
		};
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		refresh = (MyRefreshListView) findViewById(R.id.refreshview);
		refresh.setOnItemClickLintener(this);
		refresh.setAdapter(new MyAdapter(this));
		refresh.setOnRefreshingCallback(new OnRefreshing() {
			
			@Override
			public void callback() {
				// TODO Auto-generated method stub
				new Thread(){
					public void run(){
						try{
							Thread.sleep(3000);
						}catch(Exception e){
							
						}
						handler.sendEmptyMessage(0);
					}
				}.start();
			}
		});
	}
	
	class MyAdapter extends BaseAdapter{
		private LayoutInflater inflater;
		public MyAdapter(Context context){
			inflater = LayoutInflater.from(context);
		}
		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return 20;
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			// TODO Auto-generated method stub
			TextView t;
			if(convertView == null){
				convertView = inflater.inflate(R.layout.activity_list_item, null);
				t = (TextView) convertView.findViewById(R.id.textView1);
				convertView.setTag(t);
			}
			else{
				t = (TextView) convertView.getTag();
			}
			t.setText("this is "+position);
			return convertView;
		}
		
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) {
		// TODO Auto-generated method stub
		Log.w("family_log", "in onitemclicklistener position  = "+position);
	}
}


原始碼連結 :