双层布局 DoubleLayerLayout
来源:互联网 发布:淘宝店铺白色导航制作 编辑:程序博客网 时间:2024/04/30 07:58
前言
之前用过赶集生活 App,主界面向下滑动可以露出天气信息。效果不错。不仅充分的利用了空间,也给用户以发现的乐趣。所以,我也做了一个这样的布局。
效果图
思路
DoubleLayerLayout 继承自 RelativeLayout。正常情况下,foreground view 挡住 background view。滑动时,让 foreground 跟随手指移动,露出 background view。同时,关注手指移动的加速度,实现“猛地”一滑,foreground view 顺势滑开的效果。
参考链接
链接1
知识点
- View 中几个比较重要的 hook 的调用顺序:
onFinishInflate();
onAttachedToWindow();
onWindowVisiblityChanged();
onMeasure();
onSizeChanged();
onLayout();
onDraw(); - 打算处理手势之前,触发一个cancelEvent
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()); } @Override protected void onFinishInflate() { super.onFinishInflate(); bgView = getChildAt(0); fgView = getChildAt(1); } @Override protected 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; } @Override public 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 fgView float 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(); } @Override protected void applyTransformation(float interpolatedTime, Transformation transformation) { int dy = (int) (interpolatedTime * this.dy); view.layout(l, t + dy, r, t + h + dy); } }}
0 0
- 双层布局 DoubleLayerLayout
- 双层布局 DoubleLayerLayout (续)
- 关于ListView嵌套双层布局
- position的应用(双层背景,靠底边布局)
- 如何创建环型、树型双层布局
- 仿格瓦拉双层拖拽布局,格瓦拉电影详情界面
- 双层循环
- 双层汉诺塔
- 双层桶
- 双层桶
- 双层表格
- DataGrid显示双层表头
- 立体双层车库
- 双层嵌套GridView
- 双层路由器联网
- 双层HashMap实现检索
- extjs双层表头
- 关于双层for循环
- SQLite历史
- 【BZOJ 1102】 [POI2007]山峰和山谷Grz
- BIRT 报表的自动化测试
- google-glog库编译(Visual Studio 2013)及使用方法
- java 枚举类型enum 的使用
- 双层布局 DoubleLayerLayout
- Android使用VideoView播放网络视频,获取网络视频缩略图
- [UnityShader3]遮罩效果
- linux简单的字符设备驱动程序(写的很清晰)
- 在Windows上使用putty连接一台Linux主机
- SpringSecurity核心组件
- 数据库第一次作业参考答案
- android lichee编译脚本解析
- 基于go+protobuf实现的多种持久化方案的mq框架:kiteq