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 相关知识
![](https://img.haomeiwen.com/i4267785/b87b90116c3265a8.png)
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 {
}
![](https://img.haomeiwen.com/i4267785/4e99aa7b2c6ae33c.png)
2.2 Android UI视图架构
在每一个Activity中都包含了一个Window,而这个Window通常上是由PhoneWindow实现的,而PhoneWindow又将DecorView设置为整个界面的根布局,DecorView作为根布局将要显示的具体内容呈现在PhoneWindow上,并提供了一些通用方法来操作界面。这里所有View的交互事件都由WindowManagerService(WMS)进行接收,并通过Activity回调相应的onClickListener。
![](https://img.haomeiwen.com/i4267785/5a846cdbbf0116a9.png)
2.3.Android坐标系与视图坐标系
在Android的世界中我们最常用到的就是Android坐标系和视图坐标系了。对于一个控件而言,它在Android坐标系中的位置我们可以称之为:绝对坐标系;而在视图坐标系中,指示的就是它的相对位置了。
![](https://img.haomeiwen.com/i4267785/6da703295139143f.png)
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);
}
网友评论