今天讲解一下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请猛戳