1. 程式人生 > >Android進階篇之ListView、GridView以及ScrollView實現按鈕控制滾動

Android進階篇之ListView、GridView以及ScrollView實現按鈕控制滾動

這次還是一樣,因為專案需要,需要對滾動檢視需要手動控制,也就是點選上下左右按鈕,能讓滾動控制元件觸發對應的操作

在android中,滾動View最基本的有三種,分別是:ListView、GridView和ScrollView

先看效果圖:1、ListView的效果圖,右下角放置滾動控制按鈕


2、GridView的效果圖


3、ScrollView 的效果圖就不上傳了,因為都差不多。

是不是看完效果圖覺得弱爆了,那就對了,因為現在的功能就是實現了上下滾動,如果對上面那兩個按鈕加上下拉載入和上拉重新整理呢?甚至還可以控制當在最頂部時只顯示“下”的Button,還可以做當整個滾動檢視沒有超過一屏時的監聽

廢話不多說,現在來上程式碼。

第一步:

編寫佈局檔案-->>>>檔名為common_item_menu_scorll_btns.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" >
    
    <Button 
        android:id="@+id/common_menu_scroll_up"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/common_menu_scroll_up_selector"/>
    <Button 
        android:id="@+id/common_menu_scroll_down"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/common_menu_scroll_down_selector"/>
</LinearLayout>

第二步:

編寫自定義檢視,因為ListView和GridView都是繼承AbsListView,所以可以把需要控制的型別由三個變成兩個

/**
 * 如果需要載入更多的滾動檢視就需要設定OnAddMoreDataListener
 * @author yejihuang
 */
public class ScrollBtnView extends LinearLayout implements OnClickListener{

	private Context mContext ;
	private ScrollView scroll ;
	private AbsListView mAbsListView ;
	public int selectIndex ; 
	private boolean isListBottom ;
	public boolean isListTop ;
	private int type ;
	
	private Hodler hodler ;
	
	private OnScrollBtnListener onScrollBtnListener ;
	private OnOpratorScrollBtnListener onOpratorScrollBtnListener ;
	
	/**
	 * 如果不需要載入更多功能請使用ScrollBtnView(Context context, Object obj)
	 * 需要請使用ScrollBtnView(Context context, Object obj, OnOpratorScrollBtnListener onOpratorScrollBtnListener)
	 * @param context 上下文物件
	 * @param obj 需要被控制滾動的物件,在這裡只寫了三種,ScrollView,ListView,GridView
	 */
	public ScrollBtnView(Context context, Object obj) {
		super(context);
		mContext = context ;
		initData() ;
		initView() ;
		getObject(obj) ;
	}
	/**
	 * 如果不需要載入更多功能請使用ScrollBtnView(Context context, Object obj)
	 * 需要請使用ScrollBtnView(Context context, Object obj, OnOpratorScrollBtnListener onOpratorScrollBtnListener)
	 * @param context 上下文物件
	 * @param obj 需要被控制滾動的物件,在這裡只寫了三種,ScrollView,ListView,GridView
	 */
	public ScrollBtnView(Context context, Object obj, OnOpratorScrollBtnListener onOpratorScrollBtnListener) {
		super(context);
		mContext = context ;
		initData() ;
		initView() ;
		getObject(obj) ;
		this.onOpratorScrollBtnListener = onOpratorScrollBtnListener ;
	}

	private void initView() {
		View view = LayoutInflater.from(mContext).inflate(R.layout.common_item_menu_scorll_btns, this, true) ;
		view.setVisibility(View.GONE) ;
		hodler = new Hodler() ;
		hodler.view = view ;
		hodler.upBtn = (Button) view.findViewById(R.id.common_menu_scroll_up) ;
		hodler.downBtn = (Button) view.findViewById(R.id.common_menu_scroll_down) ;
		hodler.upBtn.setOnClickListener(this) ;
		hodler.downBtn.setOnClickListener(this) ;
		if (isListTop)
			hodler.upBtn.setVisibility(View.GONE) ;
	}
	
	private void initData() {
		this.selectIndex = 0 ;
		isListTop = true ;
	}
	
	/**
	 * 根據傳入的物件判斷是哪一種滾動,然後強制轉換
	 * @param obj
	 */
	private void getObject(Object obj) {
		
		if (obj instanceof ScrollView) {
			this.type = ScrollBtnConstant.TYPE_SCROLL ;
			this.scroll = (ScrollView) obj ;
			this.scroll.setOnTouchListener(new OnTouchListener() {
				private int lastY = 0;
				private int touchEventId = -9983761;
				Handler handler = new Handler() {
					@Override
					public void handleMessage(Message msg) {
						super.handleMessage(msg);
						View scroller = (View) msg.obj;
						if (msg.what == touchEventId) {
							if (lastY == scroller.getScrollY()) {
								//停止了,此處你的操作業務
								refreshCtrlScrollBtn();
							} else {
								handler.sendMessageDelayed(handler.obtainMessage(touchEventId, scroller), 1);
								lastY = scroller.getScrollY();
							}
						}
					}
				};
				@Override
				public boolean onTouch(View v, MotionEvent event) {
					int eventAction = event.getAction();
					int y = (int) event.getRawY();
					switch (eventAction) {
					case MotionEvent.ACTION_UP:
						handler.sendMessageDelayed(handler.obtainMessage(touchEventId, v), 5);
						break;
					default:
						break;
					}
					return false;
				}


			});
			hodler.view.setVisibility(View.VISIBLE) ;
		} else if (obj instanceof AbsListView) {
			this.type = ScrollBtnConstant.TYPE_LIST ;
			this.mAbsListView = (AbsListView) obj ;
			MainHandler.post2Main(new Runnable() {	
				@Override
				public void run() {
					mAbsListView.setOnScrollListener(new OnScrollListener() {
						@Override
						public void onScrollStateChanged(AbsListView view, int scrollState) {
							if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
								selectIndex = mAbsListView.getFirstVisiblePosition() ;
								refreshCtrlScrollBtn() ;
							}
							if(onScrollBtnListener != null){
								onScrollBtnListener.onScrollStateChanged(view, scrollState) ;
							}
						}
						
						@Override
						public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
							if(totalItemCount <= visibleItemCount){
								hodler.view.setVisibility(View.GONE) ;
							} else {
								hodler.view.setVisibility(View.VISIBLE) ;
							}
							if(onScrollBtnListener != null){
								onScrollBtnListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
							}
						}
					}) ;
				}
			}, 1500) ;
		}
	}
	
	public void setOnOpratorScrollBtnListener(
			OnOpratorScrollBtnListener onOpratorScrollBtnListener) {
		this.onOpratorScrollBtnListener = onOpratorScrollBtnListener;
	}
	
	/**
	 * 攔截觸控事件,以免觸控到地圖層
	 */
	@Override
	public boolean onTouchEvent(MotionEvent arg0) {
		return true;
	}

	@Override
	public void onClick(View v) {
		int direct ;
		if (v.getId() == R.id.common_menu_scroll_up)
			direct = ScrollBtnConstant.UP ;
		else
			direct = ScrollBtnConstant.DOWN ;
		//執行上下滾動事件
		switch (direct) {
		case ScrollBtnConstant.UP:
			switch (type) {
			case ScrollBtnConstant.TYPE_SCROLL:
				scroll.smoothScrollBy(0, ScrollBtnConstant.DEFAULT_DISTANCE_UP) ;
				break;
			case ScrollBtnConstant.TYPE_LIST:
				if (selectIndex > 0) {
					selectIndex = mAbsListView.getFirstVisiblePosition() ;
					selectIndex -- ;
				}
				mAbsListView.smoothScrollToPosition(selectIndex);
				break;
			}
			break;
		case ScrollBtnConstant.DOWN:
			switch (type) {
			case ScrollBtnConstant.TYPE_SCROLL:
				scroll.smoothScrollBy(0, ScrollBtnConstant.DEFAULT_DISTANCE_DOWN) ;
				break;
			case ScrollBtnConstant.TYPE_LIST:
				if (selectIndex < mAbsListView.getCount() - 1) {
					selectIndex = mAbsListView.getLastVisiblePosition() ;
					selectIndex ++ ;
					isListBottom = false ;
				} else {
					isListBottom = true ;
				}
				if (!isListBottom) { // 如果是滑動到了最底部,點擊向下繼續滾動
					mAbsListView.smoothScrollToPosition(selectIndex);
				} else { //如果已經到最底部,再點擊向下,就重新整理資料
					if (!NullUtils.isNull(onOpratorScrollBtnListener) 
							&& onOpratorScrollBtnListener.doLoadMore()) {
						selectIndex ++ ;			//一定是放在重新整理之後
						mAbsListView.smoothScrollToPosition(selectIndex);
					}
				}
				break;
			}
			break;
		default:
			break;
		}
		refreshCtrlScrollBtn();
	}

	public void refreshCtrlScrollBtn() {
		//執行up按鈕隱藏和出現的邏輯
		switch (type) {
		case ScrollBtnConstant.TYPE_SCROLL:
			if (scroll.getScrollY() == 0) {
				isListTop = true ;
				hodler.upBtn.setVisibility(View.GONE) ;
			} else {
				isListTop = false ;
				hodler.upBtn.setVisibility(View.VISIBLE) ;
			}
			break;
		case ScrollBtnConstant.TYPE_LIST:
			int top = mAbsListView.getChildAt(0).getTop() ;
			int distance = mAbsListView.getChildAt(0).getHeight() / 2 ;
			if (selectIndex <= 0) {
				if (top > (-1) * distance) {   //對滾動距離小於item高度的一半的時候,彈回頂部,當滾動距離大於一半切沒有超出下一個item就自動滾動到下一個item
					isListTop = true ;
					mAbsListView.setSelection(0) ;
					hodler.upBtn.setVisibility(View.GONE) ;
				} else {
					isListTop = false ;
					mAbsListView.setSelection(1) ;
					hodler.upBtn.setVisibility(View.VISIBLE) ;
				}
			} else {
				isListTop = false ;
				hodler.upBtn.setVisibility(View.VISIBLE) ;
			}
			break;
		}
	}
	
	/**
	 * 新增一個載入更多重新整理函式的介面
	 * @author yejihuang
	 *
	 */
	public interface OnOpratorScrollBtnListener {
		/**
		 * 載入更多
		 * @return
		 */
		public boolean doLoadMore () ;
	}
	
	/**
	 * 這個介面是把對傳入的滾動控制元件,所觸發的滾動監聽分發出去
	 * @author yejihuang
	 *
	 */
	public interface OnScrollBtnListener {
		public void onScrollStateChanged(AbsListView view, int scrollState) ;
		public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) ;
	}
	
	public void setOnScrollBtnListener(OnScrollBtnListener onScrollBtnListener) {
		this.onScrollBtnListener = onScrollBtnListener;
	}
	
	class Hodler {
		View view ;
		Button upBtn ;
		Button downBtn ;
	}
	
	class ScrollBtnConstant {
		/**
		 * 預設點選一次滾動的距離
		 */
		public static final int DEFAULT_DISTANCE_DOWN = 200 ;
		public static final int DEFAULT_DISTANCE_UP = -200 ;
		public static final int DOWN = 1 ;
		public static final int UP = 2 ;
		
		public static final int TYPE_SCROLL = 1 ;
		public static final int TYPE_LIST = 2 ;
	}
}

程式碼中NullUtils.isNull()只是一個判斷物件是否是NULL的靜態函式,如果使用直接換成Object != null就可以了

第三步:

滾動控制的按鈕檢視寫好了,現在就是直接新增到自己想要的地方就可以,先看看在listview佈局檔案中怎麼新增,加一個LinearLayout佈局容器來裝那個滾動控制檢視,

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout01"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ListView
        android:id="@+id/MyListView"
        android:divider="@drawable/sslist_driver"   
    	android:dividerHeight="1dip"   
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    </ListView>

    <LinearLayout
        android:id="@+id/scroll_btns"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true">
        
    </LinearLayout>
</RelativeLayout>

然後在Java程式碼中動態新增
LinearLayout linear = (LinearLayout) findViewById(R.id.scroll_btns) ;
linear.addView(new ScrollBtnView(this, list)) ;
此處的list是指你想要控制的listview的物件

如果想控制GridView那就把list改成GridView 的例項物件就可以了,簡單吧!

現在來說說當滾動到了最底部,繼續點擊向下就載入更多資料。

只要實現onOpratorScrollBtnListener監聽器就可以了

可以從程式碼中看出有兩種方式,多加一行setOnOpratorScrollBtnListener程式碼和實現帶onOpratorScrollBtnListener的建構函式就可以了

有什麼問題,歡迎小夥伴們參與討論!