@myron-lee
2015-03-17T06:41:40.000000Z
字数 4357
阅读 1776
Blog
之前用过赶集生活 App,主界面向下滑动可以露出天气信息。效果不错。不仅充分的利用了空间,也给用户以发现的乐趣。所以,我也做了一个这样的布局。
DoubleLayerLayout 继承自 RelativeLayout。正常情况下,foreground view 挡住 background view。滑动时,让 foreground 跟随手指移动,露出 background view。同时,关注手指移动的加速度,实现“猛地”一滑,foreground view 顺势滑开的效果。
MotionEvent cancelEvent = MotionEvent.obtain(ev);cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (ev.getActionIndex()<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));onTouchEvent(cancelEvent);
package com.example.com.example.widget;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.animation.AccelerateDecelerateInterpolator;import android.view.animation.Animation;import android.view.animation.Transformation;import android.widget.RelativeLayout;import android.widget.Scroller;public class DoubleLayerLayout extends RelativeLayout {private static final int SNAP_VELOCITY_THRESHOLD = 600;private static final int DURATION = 200;private View bgView;private View fgView;private Scroller scroller;private VelocityTracker velocityTracker;private float lastY;private int originalTop;/*** if totalDy > dyThreshold, show {@link #bgView}*/private float dyThreshold;public DoubleLayerLayout(Context context) {super(context);init();}public DoubleLayerLayout(Context context, AttributeSet attrs) {super(context, attrs);init();}public DoubleLayerLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init(){scroller = new Scroller(getContext());}@Overrideprotected void onFinishInflate() {super.onFinishInflate();bgView = getChildAt(0);fgView = getChildAt(1);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);originalTop = getTop();dyThreshold = getHeight()*0.25f;}@Overridepublic boolean onTouchEvent(MotionEvent event) {// return super.onTouchEvent(event);if (super.onTouchEvent(event)) {return true;}addVelocityTracker(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:handleDownEvent(event);break;case MotionEvent.ACTION_MOVE:handleMoveEvent(event);break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:handleUpEvent(event);break;}return true;}private void handleDownEvent(MotionEvent ev) {lastY = ev.getY();}private void handleMoveEvent(MotionEvent ev) {// update the position of fgViewfloat currY = ev.getY();float dy = currY - lastY;lastY = currY;fgView.layout(fgView.getLeft(), ((int) (fgView.getTop() + dy)), fgView.getRight(), ((int) (fgView.getTop() + getMeasuredHeight() + dy)));// fgView.scrollBy(0, (int) -dy);}private void handleUpEvent(MotionEvent ev) {float totalDy = fgView.getTop() - originalTop;float snapVelocity = getYVelocity();if ((totalDy < dyThreshold && snapVelocity < SNAP_VELOCITY_THRESHOLD) || snapVelocity < -SNAP_VELOCITY_THRESHOLD){// reset// fgView.layout(fgView.getLeft(), originalTop, fgView.getRight(), originalTop+getMeasuredHeight());animateLayout(fgView, originalTop-fgView.getTop());} else {// show bgView// fgView.layout(fgView.getLeft(), ((int) (originalTop + getMeasuredHeight() * 0.5f)), getRight(), ((int) (originalTop + getMeasuredHeight() * 1.5f)));animateLayout(fgView, ((int) (originalTop + getMeasuredHeight() * 0.5f - fgView.getTop())));}recycleVelocityTracker();}private void animateLayout(View view, int dy){Animation layoutAnimation = new LayoutAnimation(view, dy);layoutAnimation.setDuration(DURATION);layoutAnimation.setInterpolator(new AccelerateDecelerateInterpolator());startAnimation(layoutAnimation);}private void addVelocityTracker(MotionEvent event) {if (velocityTracker == null) {velocityTracker = VelocityTracker.obtain();}velocityTracker.addMovement(event);}private void recycleVelocityTracker() {if (velocityTracker != null) {velocityTracker.recycle();velocityTracker = null;}}private int getYVelocity() {velocityTracker.computeCurrentVelocity(1000);int velocity = (int) velocityTracker.getYVelocity();return velocity;}class LayoutAnimation extends Animation {private View view;private int dy;private int t;private int h;private int l;private int r;public LayoutAnimation(View view, int dy) {super();this.view = view;this.dy = dy;t = view.getTop();l = view.getLeft();r = view.getRight();h = view.getMeasuredHeight();}@Overrideprotected void applyTransformation(float interpolatedTime,Transformation transformation) {int dy = (int) (interpolatedTime * this.dy);view.layout(l, t + dy, r, t + h + dy);}}}