[转] android自定义布局中的平滑移动
文章主要讲的是自定义view的写法心得。
转自:http://www.apkbus.com/android-48445-1-1.html
在android应用程序的开发过程中,相信我们很多人都想把应用的交互做的比较绚丽,比如让界面切换平滑的滚动,还有热度灰常高的伪3D等界面效果,通常情况下,系统提供的应用在特效这方面只能为我们提供简单的动画接口,所以要想实现比较酷炫的效果还是要自己去开发布局控件(即所谓的自定义View、ViewGroup)。小弟也经常做一些自定义的控件,最近工作比较清闲,所以便将自己对自定义布局控件的一些心得写出来,权当是自己的学习笔记了,各位高手看到了可以忽略。下面就我最近工作中遇到的一个自定义控件开发做一些简单的介绍,其实那个地方原本可以用ScrollView解决很大一部分问题的,但有一些效果确实需要对控件进行重新定义,在继承ScrollView开发中仍然会遇到一些ScrollView自身的限制,所以就仿照ScrollView自己做了一个控件。在其中遇到了一些问题自然就是像ScrollView中拖动的效果(比如快速拖动在手指离开屏幕时控件依旧会由于惯性继续滑动一段距离后才会停止运动),所以就对这个东东做了一下仔细的研究,虽然以前也做过类似的开发,这次由于时间比较充裕,所以将开发中遇到的一些问题都一一记录了下来。下面开始正题:
自定义布局控件自然是要继承某个View或ViewGroup
由于是根据项目的开发来写的这篇博客,所以我就以自定义布局控件(ViewGroup)来做介绍了。
开发一个自定义的ViewGroup自然是要继承ViewGroup类了,在继承这个类之后必须要重写的方法就是
onLayout(boolean changed, int l, int t, int r, int b)
另外至少要有一个构造方法,我个人习惯重写那个有两个参数的构造方法(XXX(Context context, AttributeSet attrs)),因为有了这个构造方法就可以在xml布局文件里使用这个类了。
如果想要对这个布局控件以及其子控件的尺寸进行精确的控制那就要重写下面这个方法了
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
这个方法从字面理解就是估算控件的尺寸大小了,关于这个方法的详细说明引用一下另一位童鞋的文章http://www.eoeandroid.com/thread-102385-1-1.html,这里就不详细介绍了
下面开始介绍关于如何让自定义的控件进行平滑的移动,并能够根据手势的情况产生惯性滑动的效果
先介绍一下开发这种滑动效果需要用到的各种工具类:
android.view.VelocityTracker
android.view.Scroller
android.view.ViewConfiguration
VelocityTracker从字面意思理解那就是速度追踪器了,在滑动效果的开发中通常都是要使用该类计算出当前手势的初始速度(不知道我这么理解是否正确,对应的方法是velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity))并通过getXVelocity或getYVelocity方法得到对应的速度值initialVelocity,并将获得的速度值传递给Scroller类的fling(int
startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) 方法进行控件滚动时各种位置坐标数值的计算,API中对fling 方法的解释是基于一个fling手势开始滑动动作,滑动的距离将由所获得的初始速度initialVelocity来决定。关于ViewConfiguration 的使用主要使用了该类的下面三个方法:
configuration.getScaledTouchSlop() //获得能够进行手势滑动的距离
configuration.getScaledMinimumFlingVelocity()//获得允许执行一个fling手势动作的最小速度值
configuration.getScaledMaximumFlingVelocity()//获得允许执行一个fling手势动作的最大速度值
需要重写的方法至少要包含下面几个方法:
onTouchEvent(MotionEvent event)//有手势操作必然少不了这个方法了
computeScroll()//必要时由父控件调用请求或通知其一个子节点需要更新它的mScrollX和mScrollY的值。典型的例子就是在一个子节点正在使用Scroller进行滑动动画时将会被执行。所以,从该方法的注释来看,继承这个方法的话一般都会有Scroller对象出现。
在往下就是介绍比较具体的开发思路
首先我们要初始化一些变量,其中的多数代码已经在上面做出介绍了
void init(Context context) {
mScroller = new Scroller(getContext());
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setWillNotDraw(false);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); }
public void fling(int velocityY) {
if (getChildCount() > 0) {
mScroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0,
maxScrollEdge);
final boolean movingDown = velocityY > 0;
awakenScrollBars(mScroller.getDuration());
invalidate();
}
}
private void obtainVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
} private void releaseVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN
&& event.getEdgeFlags() != 0) {
return false;
} obtainVelocityTracker(event); final int action = event.getAction();
final float x = event.getX();
final float y = event.getY(); switch (action) {
case MotionEvent.ACTION_DOWN:
LogUtil.log(TAG, "ACTION_DOWN#currentScrollY:" + getScrollY()
+ ", mLastMotionY:" + mLastMotionY,
LogUtil.LOG_E);
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionY = y;
break; case MotionEvent.ACTION_MOVE:
final int deltaY = (int) (mLastMotionY - y);
mLastMotionY = y;
if (deltaY < 0) {
if (getScrollY() > 0) {
scrollBy(0, deltaY);
}
} else if (deltaY > 0) {
mIsInEdge = getScrollY() <= childTotalHeight - height;
if (mIsInEdge) {
scrollBy(0, deltaY);
}
}
break; case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity(); if ((Math.abs(initialVelocity) > mMinimumVelocity)
&& getChildCount() > 0) {
fling(-initialVelocity);
} releaseVelocityTracker();
break;
} return true;
}
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
int scrollX = getScrollX();
int scrollY = getScrollY();
int oldX = scrollX;
int oldY = scrollY;
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
scrollX = x;
scrollY = y;
scrollY = scrollY + 10;
scrollTo(scrollX, scrollY);
postInvalidate();
}
}
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
invalidate();
}
}
}
[转] android自定义布局中的平滑移动的更多相关文章
- 从零开始学android开发-布局中 layout_gravity、gravity、orientation、layout_weight
线性布局中,有 4 个及其重要的参数,直接决定元素的布局和位置,这四个参数是 android:layout_gravity ( 是本元素相对于父元素的重力方向 ) android:gravity (是 ...
- android 在布局中动态添加控件
第一步 final LayoutInflater inflater = LayoutInflater.from(this); 第二步:获取需要被添加控件的布局 final LinearLayout l ...
- Android 自定义Adapter中实现startActivityForResult的分析
最近几天在做文件上传的时候,想在自定义Adapter中启动activity时也返回Intent数据,于是想到了用startActivityForResult,可是用mContext怎么也调不出这个方法 ...
- Android 自定义view中的属性,命名空间,以及tools标签
昨日看到有人在知乎上问这3个琐碎的小知识点,今天索性就整理了一下,其实这些知识点并不难,但是很多开发者平时很少注意到这些, 导致的后果就是开发的时候 经常会被ide报错,开发效率很低,或者看开源代码的 ...
- Android自定义布局的背景在多分辨率的情况下设置fill_parent时背景不能够横向全屏的问题解决
问题描述:最近做了一个自定义的控件LinearLayout就是公用的底部菜单条,在指定分辨率下(例如:480x800,480x854)下背景是正常的,但是当程序运行到非指定(默认)的分辨率下就不正常了 ...
- android 自定义view中findViewById为空的解决办法
网上说的都是在super(context, attrs);构造函数这里少加了一个字段, 其实根本不只这一个原因,属于view生命周期的应该知道,如果你在 自定义view的构造函数里面调用findVie ...
- Android 自定义seekbar中,thumb被覆盖掉一部分问题
(图一) (图二) (图三) 做一个自定义的seekbar,更改其背景图片: <com.android.Progress android:id="@+id/focus_seek ...
- Android 自定义Dialog中加EditText弹不出键盘跟Dialog遮挡键盘的问题
先上两张图 第一张问题很明显,第二张是成功的图, 其实第一张是加了 //getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INP ...
- android布局中显示隐藏动画
android 在布局中提供属性,能简单的加入动画效果,例如以下: <LinearLayout ... animateLayoutChanges="true" ... /&g ...
随机推荐
- 2019-3-8-win10-uwp-一张图说明水平对齐和垂直对齐
title author date CreateTime categories win10 uwp 一张图说明水平对齐和垂直对齐 lindexi 2019-03-08 10:45:40 +0800 2 ...
- html 输入框显示“小叉叉”的清空方法
在IE10以下,我们的输入框input会出现小叉叉.怎么解决这个问题呢? 针对input框我们做一个处理 <style type="text/css"> input:: ...
- Thinkphp 错误集锦
1.无法加载控制器 开始还跑TP核心文件中找错误,结果没找到什么结果.最后还是用程序新建模块才发现问题. 问题是命名空间名字写错了.比如书:本来是Report模块下的IndexContrller,但是 ...
- git与github建立链接(将本次项目与网络GitHub同步)(二)
第一步:我们需要先创建一个本地的版本库(其实也就是一个文件夹). 你可以直接右击新建文件夹,也可以右击打开Git bash命令行窗口通过命令来创建. 现在我通过命令行在桌面新建一个TEST文件夹(你也 ...
- 在vscode中使用字体Cascadia Code
下载字体 下载地址:github:https://github.com/microsoft/cascadia-code/releases 安装字体(windows10) 设置 > 个性化 > ...
- 华为 Mate8 Emui 5.0 安卓 7.0 root 记录
步骤: 0.备份手机全部资料 1.华为官网申请解锁码 (unlock password) http://emui.huawei.com/plugin/hwdownload/download 2.关闭手 ...
- Mysql千万级访问量架构
1.HTML 静态化 其实大家都知道,效率最高.消耗最小的就是纯静态化的html页面,所以我们尽可能是我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法.但是对于大量内容并且频 ...
- easyui combobox下拉框中显示大于号小于号的问题
前两天同事做了个功能,通过勾选下拉框里的值进行列表查询,结果下拉框里的值是“0<t<=2”.“2<t<=5”.“t>5”这样的. combobox是用脚本渲染出来的,里面 ...
- Leetcode645.Set Mismatch错误的集合
集合 S 包含从1到 n 的整数.不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复. 给定一个数组 nums 代表了集合 S ...
- js对象属性方法大总结
数组(Array):系列元素的有序集合: 详细演示请看:[js入门系列演示·数组 ] http://www.cnblogs.com/thcjp/archive/2006/08/04/467761.ht ...