Android艺术开发探索——3.View基础
作者:互联网
3.1 什么是View
View是Android中所有控件的基类,是一种界面层的控件的一种抽象,本身可以是单个控件也可以是由多个控件组成的一组控件。
3.1.1 View的位置参数
这些坐标都是相对于view的父容器来说的,是一种相对坐标
后来增加了x,y,translationX,translationY,x,y是view左上角的坐标,translationX,translationY是view左上角相对于父容器的偏移量,默认值为0,
x = left + translationX
y = top + translationY
1.获取view左上角相对于父容器的坐标,当view没有发生平移时,getX() == getLeft(),getY() == getTop(),当发生平移时,top和left表示的是原始左上角的位置信息,其值并不会发生改变,此时发生改变的是x,y,translationX,translationY。
3.1.2 MotionEvent
1.手指接触屏幕后所产生的一系列事件
事件类型 | 具体动作 |
---|---|
ACTION_DOWN | 手指刚接触屏幕 |
ACTION_MOVE | 手指在屏幕上移动 |
ACTION_UP | 手指从屏幕上松开的一瞬间 |
ACTION_CANCEL | 结束事件(非人为原因) |
- 点击屏幕后离开松开 —— DOWN -> UP
- 点击屏幕滑动一会再松开 —— DOWN -> MOVE ->…->MOVE ->UP
2.通过MotionEvent对象我们可以得到点击事件的x和y坐标。
getX/getY 相对于当前View左上角的x和y坐标,getRawX/getRawY 相对于手机屏幕左上角的x和y坐标
3.1.3 TouchSlop
系统所能识别出的被认为是滑动的最小距离,是个常量,和设备有关,在不同设备上这个值可能是不同的,可通过ViewConfiguration.get(getContext()).getScaledTouchSlop()获得,可利用这个常量做一些过滤。
3.1.4 VelocityTracker
速度追踪,用于追踪手指在滑动过程中的速度,包括水平方向和竖直方向。
//在View的onTouchEvent方法中追踪当前点击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
//获得当前的速度
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
//当不需要使用时,调用clear方法来重置并回收内存
velocityTracker.clear();
velocityTracker.recycle();
1.获取速度之前先计算速度computeCurrentVelocity()
2.这里的速度是指一段时间内手指划过的像素数
3.和Android坐标轴相同方向结果为正,相反方向为负
3.1.5 GestureDetector
手势检测,用于辅助检测用户的单击,滑动,长按,双击等行为
GestureDetector内部的Listener接口:
- OnGestureListener,这个Listener监听一些手势,单击,滑动,长按
- OnDoubleTapListener,监听双击和单击事件
- OnContextClickListener,鼠标右键,加入外设
- SimpleOnGestureListener,实现了上面三个接口的类,拥有上面三个的所有回调方法
使用:
- 实例化GestureDetectorCompat类
- 实现接口
- 接管目标View的onTouchEvent方法
3.1.6 Scroller
弹性滑动对象,用于实现view的弹性滑动。scrollTo/scrollBy进行滑动时,其过程是瞬间完成的,Scroller来实现有过渡效果的滑动,若要实现弹性滑动,需要和View的computeScroll方法配合使用。
3.2 View的滑动
实现滑动的三种方式:
1.通过View本身提供的scrollTo / scrollBy方法
2.通过动画给View施加平移效果
3.通过改变View的LayoutParams使View重新布局从而实现滑动
3.2.1 使用scrollTo / scrollBy
/**
* Set the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the x position to scroll to
* @param y the y position to scroll to
*/
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
/**
* Move the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the amount of pixels to scroll by horizontally
* @param y the amount of pixels to scroll by vertically
*/
public void scrollBy(int x, int y) { //可以看出scrollBy也是调用scrollBy实现的
scrollTo(mScrollX + x, mScrollY + y);
}
scrollBy:基于当前位置的相对滑动
scrollTo:基于所传递参数的绝对滑动
mScrollX:值总是等于View左边缘和View内容左边缘在水平方向的距离
mScrollY:值总是等于View上边缘和View内容上边缘在水平方向的距离
View边缘指View位置,由四个定点组成,View内容边缘指View中内容的边缘。
scrollTo,scrollBy只能改变View内容的位置而不能改变View在布局中的位置,不能将View本身进行移动。
3.2.2 使用动画
主要操作View的translationX和translationY属性。可以采用传统的View动画,也可以采用属性动画
View动画的代码
<?xml version="1.0" encoding="UTF-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true" //希望动画后的状态得以保留
android:zAdjustment="normal">
<translate
android:duration="100" //持续时间
android:fromXDelta='0'
android:fromYDelta='0'
android:interpolator="@android:anim/linear_interpolator"
android:toXDelta="100"
android:toYDelta="100"/>
</set>
属性动画
ObjectAnimator.ofFloat(tragetView,"translationX",0,100).setDuration(100).start()
上面的动画并不能真正改变View的位置,这个View的单击事件,新位置无法触发onClick事件,单击原位置可以。
Android3.0开始,使用属性动画可以解决这个问题。
针对上面问题,有以下解决方法:在新位置预先创建一个和Button一模一样的Button,当Button完成平移动画后,把目标Button隐藏,同时把预先创建的Button显示出来
3.2.3 改变布局参数——LayoutParams
把一个Button向右平移100px:
1.将这个Button的LayoutParams里的marginLeft 参数的值增加100px;
2.在Button的左边放置一个空View,这个空View的默认宽度为0,当需要向右移动Button时,只需重新设置空View的宽度,当空View的宽度增大时,Button就自动被挤向右边。
MarginLayoutParams params = (MarginLayoutParams) button.getLayoutParams();
params.width += 500;
params.leftMargin += 500;
button.requestLayout();
//或者 button.setLayoutParams(params);
3.2.4 各种滑动方式的对比
3.3 弹性滑动
实现弹性滑动的方法有很多,共同思想将一次大的滑动分成若干次小滑动,并在一个时间段内完成。
3.3.1 Scroller
Scroller的源码
//1.创建Scroller实例
Scroller scroller = new Scroller(mContext);
//缓慢滑动到指定位置
private void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int deltaY = destY - scrollX;
//1000ms内滑向destX,效果是慢慢滑动
//2.调用startScroll()方法来初始化滚动数据并刷新界面
mScroller.startScroll(scrollX,0,deltaX,0,1000);
invalidate();
}
//3.重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
@Override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
invalidate()方法会导致View重绘,在View的draw方法中又会去调用computeScroll方法,computeScroll方法在View中是一个空实现,需要自己实现,正是因为这个computeScroll方法,View才能实现弹性滑动。总结:当View重绘后会在draw方法中调用computeScroll,computeScroll会去向Scroller获取当前的scrollX和scrollY,然后通过scrollTo方法实现滑动;接着调用postInvalidate方法进行第二次重绘,反复直到整个滑动结束。
computeScrollOffset()方法会根据时间流逝的百分比计算出scrollX和scrollY改变的百分比并计算当前的值,返回true表示滑动未结束。
概括Scroller工作原理:需要配合View的computeScroll方法才能完成弹性滑动,不断让View重绘,每一次重绘距滑动起始时间有一个时间间隔,通过这个时间间隔Scroller可以得出View当前的滑动位置,知道滑动位置就可以通过scrollTo方法完成View的滑动。View的每一次重绘都会导致View进行小幅度的滑动。多次的小幅度滑动就组成了弹性滑动。
3.3.2 通过动画
动画本身就是一种渐进过程,通过它来实现的滑动天然就具有弹性效果
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();
100毫秒内向右移动100像素
3.3.3 使用延时策略
通过发送一系列延时消息从而达到一种渐进式效果。可以使用Handler或View的postDelayed方法,也可以使用线程的sleep方法。
postDelayed:延时发送一个消息,在消息中进行View的滑动,然后接连不断地发送这种延时消息
sleep:在while循环中不断滑动View和sleep
private static final int MESSAGE_SCROLL_TO = 1;
private static final int FRAME_COUNT = 30;
private static final int DELAYED_TIME=33;
private int mCount = 0;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg){
switch (msg.what){
case MESSAGE_SCROLL_TO:{
mCount++;
if(mCount <= FRAME_COUNT){
float fraction = mCount/(float) FRAME_COUNT;
int scrollX = (int) (fraction*100);
button.scrollTo(scrollX,0);
mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELAYED_TIME);
}
break;
}
default:
break;
}
}
};
在1000ms内将View的内容向左移动100像素
标签:探索,int,Button,scrollTo,滑动,Android,view,View 来源: https://blog.csdn.net/zhougongjinxuan/article/details/114818816