1.前言
View 官网
Provides classes that expose basic user interface classes that handle screen layout and interaction with the user.
Android 应用中的所有用户界面元素都是使用View
和ViewGroup
对象构建而成。View
对象用于在屏幕上绘制可供用户交互的内容。ViewGroup
对象用于储存其他View
和ViewGroup
对象,以便定义界面的布局。
2.View 相关知识
2.1 View/ViewGroup View树结构
在窗口中所有View都是单根继承的。你可以通过code或者XML文件来添加View。我们有许多的View的子类来用来显示和控制文本,图像或者其他的内容。
View架构:View是一种界面层的空间的一种抽象,它代表了一个控件,
除了View,还有ViewGroup,ViewGroup也继承了View,这就意味着View
本身可以是单个控件也可以是多个控件组成的一组控件。
//
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
}
// ViewGroup 继承View
public abstract class ViewGroup extends View {
}
2.2 Android UI视图架构
在每一个Activity中都包含了一个Window,而这个Window通常上是由PhoneWindow实现的,而PhoneWindow又将DecorView设置为整个界面的根布局,DecorView作为根布局将要显示的具体内容呈现在PhoneWindow上,并提供了一些通用方法来操作界面。这里所有View的交互事件都由WindowManagerService(WMS)进行接收,并通过Activity回调相应的onClickListener。
2.3.Android坐标系与视图坐标系
在Android的世界中我们最常用到的就是Android坐标系和视图坐标系了。对于一个控件而言,它在Android坐标系中的位置我们可以称之为:绝对坐标系;而在视图坐标系中,指示的就是它的相对位置了。
Android系统中为我们提供了getLocationOnScreen(int[] location)方法来获取控件在整个屏幕的绝对坐标,此时要注意的是:该坐标是从屏幕的左上角(原点)开始获取的,所以也包括了状态栏的高度
View自身的相对坐标
通过如下方法可以获得View到其父控件(ViewGroup)的距离:
方法 | 解释 |
---|---|
getTop() | 获取View自身顶边到其父布局顶边的距离 |
getLeft() | 获取View自身左边到其父布局左边的距离 |
getRight() | 获取View自身右边到其父布局左边的距离 |
getBottom() | 获取View自身底边到其父布局顶边的距离 |
getX() | 返回值为getLeft()+getTranslationX(),当setTranslationX()时getLeft()不变,getX()变。 |
getY() | 返回值为getTop()+getTranslationY(),当setTranslationY()时getTop()不变,getY()变。 |
MotionEvent提供的方法
我们看上图那个触摸点,我们知道无论是View还是ViewGroup,最终的点击事件都会由onTouchEvent(MotionEvent event)方法来处理,MotionEvent也提供了各种获取焦点坐标的方法:
方法 | 解释 |
---|---|
getX() | 获取点击事件距离控件左边的距离,即视图坐标 |
getY() | 获取点击事件距离控件顶边的距离,即视图坐标 |
getRawX() | 获取点击事件距离整个屏幕左边距离,即绝对坐标 |
getRawY() | 获取点击事件距离整个屏幕顶边的的距离,即绝对坐标 |
2.4.View的移动
1.View.scrollTo(x,y)\View.ScrollBy(x,y):内部也是调用scrollTo
2.属性动画实现:
3.位移动画:
TranslateAnimation anim = new TranslateAnimation(0, 500, 0, 500);
anim.setFillAfter(true);
anim.setDuration(2 * 1000);
button.startAnimation(anim);
4. setLayoutParams实现
5. layout实现
6. offsetLeftAndRight,offsetTopAndBottom
scrollTo,scrollBy:操作简单,适合对View内容的滑动;
view内容的点击事件,也会跟随相应滑动。
动画:操作简单,属性动画:也是很好的移动方案,移动之后,
x、y的值改变了,但是left、top、right、bottom值没有改变。
(在不考虑兼容3.0以下的版本情况下);
平移动画:主要适用于没有交互View和实现复杂的动画效果。
改变布局参数:setLayoutParams,layout,
offsetLeftAndRight,offsetTopAndBottom 适用于有交互的View。因为他们是完全移动地 View。
View的x、y、left、top、right、bottom都会相应的增加对应的px。
关于Android View的scrollBy()和scrollTo()参数传递正数却向坐标系负方向移动的特性可能很多人都有疑惑,甚至是死记结论,这里我们简单给出产生这种特性的真实原因—-源码分析,如下:
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();
}
}
}
1.调用View.scrollTo(),会触发View的onScrollChanged(int, int, int, int)} and the view will be invalidated.
2.
public void invalidate(int l, int t, int r, int b) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
//真正原因就是这里 如果正 那么值是负的方向刚好相反~
invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);
}