今天講解一下Scroller的實戰應用,此案例是在我的上一篇文章的基礎上進行開發的,如果你感覺看着有點難理解,請先閱讀《Android Scroller入門(二)》,此案例並非原創,只是在別人寫好的基礎上進行改編而來的,下面給出一張圖看一下直觀的效果。
下面我講解一下主要的地方,你可以下載我提供的Demo,然後對比着學習。
1. 因爲登陸佈局利用RelativeLayout做的,那麼我們要自定義一個佈局LoginView extends RelativieLayout,當然我們需要重寫構造函數,生成佈局然後利用scrollTo方法將它滾動到底部(隱藏)
public LoginView(Context context) {
this(context,null);
}
public LoginView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public LoginView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
/**
* 這個函數是在ViewGroup裏定義的,主要用於控制child View獲取焦點的能力,比如是否阻止child View獲取焦點。
* 他有三個常量可供設置
*
* FOCUS_BEFORE_DESCENDANTS ViewGroup本身先對焦點進行處理,如果沒有處理則分發給child View進行處理
* FOCUS_AFTER_DESCENDANTS 先分發給Child View進行處理,如果所有的Child View都沒有處理,則自己再處理
* FOCUS_BLOCK_DESCENDANTS ViewGroup本身進行處理,不管是否處理成功,都不會分發給ChildView進行處理
*/
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setFocusable(true);
mScroller = new Scroller(context);
mScreenHeigh = Utils.getWindowHeigh(context);
mScreenWidth = Utils.getWindowWidth(context);
final View view = LayoutInflater.from(context).inflate(R.layout.view_login, null);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);// 如果不給他設這個,它的佈局的MATCH_PARENT就不知道該是多少
addView(view, params);
// 背景設置成透明
setBackgroundColor(Color.argb(0, 0, 0, 0));
view.post(new Runnable() {
@Override
public void run() {
viewHeight = view.getHeight();
}
});
//滾動到底部不可見
LoginView.this.scrollTo(0, -mScreenHeigh);
ImageView btn_close = (ImageView) view.findViewById(R.id.btn_close);
btn_close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
2. 處理手指的觸摸事件,我們要重寫onTouchEvent方法
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) event.getY();
Log.d(TAG, "downY = " + downY);
//如果完全顯示的時候,讓佈局得到觸摸監聽,如果不顯示,觸摸事件不攔截,向下傳遞
if (isShow) {
return true;
}
break;
case MotionEvent.ACTION_MOVE:
moveY = (int) event.getY();
scrollY = moveY - downY;
//向下滑動
if (scrollY > 0) {
if (isShow) {
scrollTo(0, -Math.abs(scrollY));
}
} else {
if (mScreenHeigh - this.getTop() <= viewHeight && !isShow) {
scrollTo(0, Math.abs(viewHeight - scrollY));
}
}
break;
case MotionEvent.ACTION_UP:
upY = (int) event.getY();
if (isShow) {
if (this.getScrollY() <= -(viewHeight / 2)) {
startMoveAnim(this.getScrollY(), -(viewHeight - this.getScrollY()), mDuration);
isShow = false;
Log.d("isShow", "false");
} else {
startMoveAnim(this.getScrollY(), -this.getScrollY(), mDuration);
isShow = true;
Log.d("isShow", "true");
}
}
Log.d("this.getScrollY()", "" + this.getScrollY());
changed();
break;
case MotionEvent.ACTION_OUTSIDE:
Log.d(TAG, "ACTION_OUTSIDE");
break;
default:
break;
}
return super.onTouchEvent(event);
}
3.執行startMoveAnim方法滾動到指定位置
/**
* 拖動動畫
* @param startY
* @param dy 移動到某點的Y座標距離
* @param duration 時間
*/
public void startMoveAnim(int startY, int dy, int duration) {
isMoving = true;
mScroller.startScroll(0, startY, 0, dy, duration);
invalidate();//通知UI線程的更新
}
4.一旦執行startMoveAnim方法就會執行到invalidate導致view重繪,調用到computerScroll方法,完成整個滾動效果
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
// 更新界面
postInvalidate();
isMoving = true;
} else {
isMoving = false;
}
super.computeScroll();
}
5.最後要對我提供一個接口,來控制視圖的顯示和隱藏
/** 監聽接口*/
public onStatusListener statusListener;
/**
* 監聽接口,來在主界面監聽界面變化狀態
*/
public interface onStatusListener {
/** 開打狀態 */
public void onShow();
/** 關閉狀態 */
public void onDismiss();
}
下載Demo請猛戳