Android View详解(上)

Android View()——View的基础知识 目录一.View的基础知识1.什么是View2.View的位置参数3.MotionEvent4. TouchSlop5. VelocityTracker6. GestureDetector 一.View的基础知识 1.什么是View View是一种界面层的控件的一种抽象,它代表了一个控件,是Android中所有控件的基类。 2.View的位置参数 3.MotionEvent 在我们触摸屏幕的过程中,可以分为三种情况,分别是按下、滑动、弹起。Android中为我们封装好了一个MotionEvent类,使 阅读详情

第三章 View

1.View的基础知识

1.1 什么是View

View是Android所有控件的基类,比如button,listView等的基类都是View。除了View以外,还有一个ViewGroup。ViewGroup代表一组View的集合,ViewGroup也是一种View

1.2 View的参数

view的位置由四个顶点确定,分别对应四个属性top、left、right、bottom,其中top是左上角纵坐标,left是左上角的横坐标,right是右下角的横坐标,bottom是右下角的纵坐标。这些坐标是针对父容器来说的,是相对坐标。横坐标的正方向是向右,纵坐标的正方向是向下。

很容易得到如下的关系式
width=right−leftheight=bottom−top width = right - left \\ height = bottom - top width=rightleftheight=bottomtop
这些参数的获取,可以通过get方法

例如

int left=view.getLeft();

从3.0开始,新增了几个属性,分别是x、y、translationX和translationY。其中xy是左上角的坐标,translationX、translationY是view左上角与父布局的偏移量,translationX和translationY默认是0。他们的换算公式如下
x=left+translationXy=top+translationY x = left + translationX\\ y = top + translationY x=left+translationXy=top+translationY
注意如果发生平移的话,此时变化的是x和y 以及translation,left和top代表原始的view的左上角坐标,不会发生变化。

1.3 MotionEvent和TouchSlop
1.3.1 MotionEvent

代表从手指接触屏幕后的几个事件,有以下几个事件。

ACTION_DOWN——手指接触界面

ACTION_MOVE——手指在界面上移动

ACTION_UP——手指离开界面

点击—>滑动—>松开 会依次调用 ACTION_DOWN—> ACTION_MOVE—> …… ACTION_MOVE—>ACTION_UP

通过MotionEvent对象可以获取点击事件的x,y坐标;getX与getRawX两组,区别在于前者返回的是当前view左上角x、y,后者返回相对于屏幕左上角的坐标

1.3.2 TouchSlop

TouchSlop是能被系统识别的最小移动距离,这是一个常量,与设备有关,可以通过以下代码获得。

ViewConfiguration.get(getContext()).getScaledTouchSlop();

可以在frameworks/base/core/res/res/values/config.xml中找到config_viewConfigurationTouchSlop的定义,更改对应的值就可以增加识别的最小距离,防止过于灵敏。

<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
1.4 VelocityTracker、GestureDetector和Scroller
1.4.1 VelocityTracker

速度追踪,用于追踪手指滑动的速度,包括了水平和数值的速度。

使用方式:

(1)首先在view的onTouchEvent中追踪事件

@Override 
public boolean onTouchEvent(MotionEvent event) {
VelocityTracker velocityTracker=VelocityTracker.obtain();
velocityTracker.addMovement(event);
……
}

(2)获取速度。

velocityTracker.computeCurrentVelocity(1000);
int x= (int) velocityTracker.getXVelocity();
int y= (int) velocityTracker.getYVelocity();

这里的速度指的是一段时间内,手指所划过的像素数,computeCurrentVelocity的参数单位是ms,比如将时间设置1000代表的是1秒内划过的像素数。

(3)不使用时,调用clear清空

velocityTracker.clear();
velocityTracker.recycle();
1.4.2 GestureDetector

GestureDetector手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。

使用方式

(1)实现OnGestureListener接口,如果有需要还可以实现OnDoubleTapListener接口

GestureDetector gestureDetector = new GestureDetector(getContext(),
new GestureDetector.OnGestureListener() {
@Override public boolean onDown(MotionEvent e) {
return false;
}

@Override public void onShowPress(MotionEvent e) {

}

@Override public boolean onSingleTapUp(MotionEvent e) {
return false;
}

@Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
return false;
}

@Override public void onLongPress(MotionEvent e) {

}

@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
});
gestureDetector.setIsLongpressEnabled(false);

(2)接着接管目标view的onTouchEvent

@Override public boolean onTouchEvent(MotionEvent event) {
boolean flag=gestureDetector.onTouchEvent(event);
return flag;
}

(3)

方法名描述所属接口
onDown手指轻轻触摸屏幕的一瞬间,由一个ACTION_DOWN触发OnGestureListener
onShowPress手指轻轻触摸屏幕,尚未松开或拖动,由一个ACTION_DOWN触发
*注意和onDown()的区别,它强调的是没有松开或者拖动的状态
OnGestureListener
onSingleTabUp手指(轻轻触摸屏幕后)松开,伴随着一个MotionEvent.ACTION_UP而触发,这是单击行为OnGestureListener
onScroll手指按下屏幕并拖动,由1个ACTION_DOWN,多个ACTION_MOVE触发,这是拖动行为OnGestureListener
onLongPress用户长久地按屏幕不放,即长按OnGestureListener
onFling当用户按下触摸屏、快速滑动后松开,由一个ACTION,多个ACTION_MOVE和1个ACTION_UP触发,这是快速滑动行为OnGestureListener
onDoubleTap双击,由2次连续的单击组成,它不可能和onSingleTapConfirmed共存OnDoubleTapListener
onSingleTapConfirmed严格的单击行为
*注意它和onSingleTapUp地区别,如果触发了onSingleTapConfirmed,那么后面不可能再紧跟着另一个单击行为,即这只可能是单击,而不可能使双击中的一次单击
OnDoubleTapListener
onDoubleTabEvent表示发送了双击行为,再双击期间,ACTION_DOWN、ACTION_MOVE和ACTION_UP都会触发此回调OnDoubleTapListener
1.4.3 Scroller

弹性滑动对象,用于实现view的弹性滑动。区别于scrollTo和scrollBy方法进行滑动时是瞬时实现的,用户体验感较差,而Scroller可以配合View的computeScroll方法用来实现有过渡效果的滑动。

使用方式

Scroller scroller = new Scroller(mContext);
private void smoothScrollTo(int destX,int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
//1000ms内滑向dest,效果就是慢慢滑动
scroller.startScroll(scrollX,0,delta,0,1000);
invalidate();
}

@Override
public void computeScroll() {
if (scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}

具体的代码在下一节进行讲解。

2. View滑动

view的滑动有三种实现方式

2.1 使用scrollTo/scrollBy

看一下源码

可以看到scrollTo首先判断一下,首先判断判断mScrollX/Y是否等于 外部设置的x/y,不相等时,进行重新赋值,然后调用invalidateParentCaches()清空父View的缓存,用于强制父View进行视图的重建。然后调用onScrollChanged ()这个方法是scrollBy/scrollTo滚动时而产生的回调。awakenScrollBars()会启动平滑滚动的动画,动画开始时返回true。postInvalidateOnAnimation()用来在下一个动画帧上发生失效。

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();
}
}
}

可以看到scrollBy实际上就是调用了scrollTo,scrollTo使用的是绝对坐标,scrollBy是相对之前的坐标。

public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}

看代码可以发现有两个比较重要的参数mScrollX和mScrollY。

首先在说这个直接要理解一个概念就是,scrollTo和scrollBy只能改变view内容的显示位置,而不能改变view实际在布局中的位置。好比海市蜃楼能显示在很多不同的地方,但是正常这个幻想实体的地方确实固定的。mScrollX和mScrollY代表的是内容边缘到view边缘的距离。他们的关系如下所示。

mScrollX = View的左边缘 - View内容的左边缘
mScrollY = View的上边缘 - View内容的上边缘
2.2 通过动画

通过动画可以让一个view进行,使用动画进行平移则是改变translation。而动画有包括了两种,分别是传统的View动画和属性动画。如果使用属性动画,为了兼容3.0以下版本,需要使用开源的动画库nineoldandroid。

(1)view动画

先创建anim的xml文件

<?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="1000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100"
android:toYDelta="100"
android:interpolator="@android:anim/linear_interpolator"
/>
</set>

(2)属性动画

ObjectAnimator.ofFloat(view, "translationX", 0, 100).setDuration(100).start();

view动画是对动画的影象做操作,不能真正改变位置参数,如果想在动画后保存,需要加上 android:fillAfter=“true”。view动画带来了一个问题,比如一个button被移动了100的距离,然而用户点击button却没有点击事件,而点平移之前button所在位置却能触发点击事件,因为不管怎么移动,button在系统看来它的位置参数没有变动,仍然在原地,因此点击事件自然也在原地触发。而使用属性动画则不会导致这个问题。

2.3改变布局参数
ViewGroup.MarginLayoutParams layoutParams=
(ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams.leftMargin+=100;
view.requestLayout();
//或者
//view.setLayoutParams(layoutParams);
2.4三种方式的区别

scrollTo/scrollTo 使用简单,不影响点击事件。缺点是只能滑动view的内容而不能移动view。

动画 如果使用属性动画,则没有明显的缺点。如果使用view动画,则会无法和用户交互。比较复杂的动画效果需要动画才能实现。

布局参数 适合交互的view

3.弹性滑动

3.1scroller
Scroller scroller = new Scroller(mContext);
private void smoothScrollTo(int destX,int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
//1000ms内滑向dest,效果就是慢慢滑动
scroller.startScroll(scrollX,0,delta,0,1000);
invalidate();
}

@Override
public void computeScroll() {
if (scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}

使用时首先创建一个Scroller对象,然后将原坐标和目标坐标传给startScroll(),查看源码可以发现startScroll()什么都没做,只是存储了几个传递的参数。mStartX mFinalX是滑动的起点和终点 mDeltaX 是滑动的距离 mDuration是持续时间。因此可以知道startScroll其实并没有进行滑动,真正的滑动时在下面的invalidate()进行。invalidate方法会导致view的重绘,在draw过程中会调用computeScroll;然后继续这样循环,将一个大的滑动拆分成很多个小的滑动,从而实现弹性过渡的效果。

public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}

computeScroll在view中是一个空实现,需要自己进行重写。

computeScrollOffset中的代码,很容易理解 首先获取了目前已经过去的时间,在判断滑动的模式。通过Interpolator这个差值器获取动画的完成度,然后随着时间的流逝,不断地增加x、y的坐标,从而达到弹性滑动的效果。返回值为true时代表动画完成,false时代表进行中。

public boolean computeScrollOffset() {
……
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);

if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
……


return true;
}

这样可以知道,就是每次隔一段时间进行位置的计算重绘,循环进行,将一次次小的scrollTo 瞬时滑动在整个时间段上呈现出弹性滑动的效果。

3.2 通过动画

由于动画天生就是带有弹性滑动的效果,比如之前所说的下列代码可以实现100px的弹性滑动。

ObjectAnimator.ofFloat(view, "translationX", 0, 100).setDuration(100).start();

除了这个方式以外,还可以通过下面的方式进行移动。

final int startX=0;
final int deltaX=100;
ValueAnimator animator=ValueAnimator.ofInt(0,1).setDuration(1000);
animator.addUpdateListener(new AnimatorUpdateListener(){
@override
public void onAnimationUpdate(ValueAnimator animator){
//获取当前动画执行时间的百分比
float fraction=animator.getAnimatedFraction();
mButton1.scrollTo(startX+(int)(deltaX*fraction),0)
}
});
animator.start();
3.3通过延时策略

通过一个循环,不断的发送延时scrollTo达到弹性滑动的功能。

View基础知识】Android View位置参数详解 本系列文章部分摘自《Android开发艺术探索》,目的是提取精干知识点作为备忘笔记,如有侵权请及时联系我,再次感谢作者 目录 目录 View的四个顶点 View的x、y、translationX、translationY View的四个顶点 view的位置主要有四个顶点所决定,分别对应view属性的top、left、right、bottom. top:view左上角... 阅读详情

相关推荐

联想拯救者恢复出厂设置全攻略

通过本文介绍的几种方法,你可以轻松地将联想拯救者恢复到出厂系统状态。无论是通过Windows恢复选项、高级启动选项还是一键恢复功能,都能帮助你解决系统问题、清除个人信息或重置软件环境。在重置前,请务必备份重要数据,并确保了解重置的影响。重置完成后,进行适当的系统设置和软件安装,让你的联想拯救者焕然一新,继续为你提供高效、稳定的计算体验。

mmoo_python的博客 3203

android开发艺术(三)之View

Viewandroid中所有控件的基类,Button、TextView、LinearLayout共同基类都是ViewViewGroup 继承自ViewView本身可以是单个控件,也可以是多个控件组成的一组控件。

梵高话葵 1393

【人工智能 Open AI】程序员怎样提升研发效率?从技术、业务、项目管理等等多个方面来阐述。

程序员要想提升研发效率,需要从技术、业务、项目管理等多方面着手,多靠工具配合实践实现,从而提升研发效率。

AI天才研究院 5491

Android View使用、自定义和性能优化

Android中的视图类可分为3种:「布局(Layout)类」、「视图容器(View Container)类」和「视图类(例TextView)」,这3种类都是android.view.View的子类。ViewGroup是一个容器类,该类也是View的重要子类,所有的布局类和视图容器类都是ViewGroup的子类,而视图类直接继承自View类。

帅次的博客 4093

Android View解析

1.View是用户接口组件的基本构建块;2.View在屏幕上占据一个矩形区域;3.View通过绘制自己与事件处理两种方式与用户交互设计View,主要是为了让应用能够与用户交互,要想完成交互,这个View就要在屏幕上占据一个矩形区域,然后利用这块屏幕区域与用户交互,交互的方式就两种,绘制自己与事件处理。自定义ViewAndroid开发中的重要概念,允许你创建不同于标准UI组件的用户界面元素。这些自定义View可以是各种形状、颜色和交互方式,完全满足你的设计需求。

Android 领域开发程序员,希望通过写博客的方式不断的总结提升自己,大家共同进步哦! 1768

Android开发-视图view讲解

view视图、容器、子viewview共有属性、代码创建view视图

zzsxyl的博客 1596

安卓 view 用法详解

一、结构     java.lang.Object       android.view.View     已知直接子类:        AnalogClock, ImageView, KeyboardView, ProgressBar, SurfaceView, TextView, ViewGroup, ViewStub     已知间接子类:       AbsListView

dahuzi的专栏 1294

Android View绘制流程详解

一、 View树的绘图流程 当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android Framework 处理。绘制是从根节点开始,对布局树进行 measure 和 draw。整个View树的绘图流程在 ViewRoot.java 类的performTraversals() 函数展开,该函数所做 的工作可简单概况为是否需要重新计算视图大小(measure)、是否需要重新安置视图的位置(layout)、以及是否需要重绘(draw),流程图如下: View 绘制流程函数调用链: .

旭哥的专栏 1658

android view 矩阵,安卓自定义 View 进阶: Matrix 详解

在上一篇文章中,我们对Matrix做了一个简单的了解,偏向理论,在本文中则会详细的讲解 Matrix 的具体用法,以及 Matrix 的一些实用技巧。Matrix方法表按照惯例,先放方法表做概览。方法类别相关API摘要基本方法equals hashCode toString toShortString比较、 获取哈希值、 转换为字符串数值操作set reset setValues getValue...

weixin_42396285的博客 688

android安卓-view.layout()过程详解,为什么view.layout()刷新控件位置

原帖: link 相比较onMeasure ,layout过程要简单多了,正如layout的中文意思“布局”中表达的一样,layout的过程就是确定View在屏幕上显示的具体位置,在代码中就是设置其成员变量mLeft,mTop,mRight,mBottom的值,这几个值构成的矩形区域就是该View显示的位置,不过这里的具体位置都是相对与父视图的位置。 与onMeasure过程类似,ViewGroup在onLayout函数中通过调用其children的layout函数来设置子视图相对与父视图中的位置,具

ruiruiddd的博客 1981

Android中Activity、View和Window关系详解

Window、Activity、View都经常用到,但三者关系还是没有系统的理清,今天咱们就开始整理整理这三者的关系:Window:顶级窗口外观和行为策略的抽象基类。唯一实现是 PhoneWindow类。Activity:四大组件之一,它提供一个界面让用户点击和各种滑动操作。View:代表用户界面组件的基本构建块,UI 组件。

allen_xu_2012_new的博客 2315

android组件view,Android View详解

什么是View?在Android中,什么是ViewViewAndroid中所有控件的基类,不管是简单的TextView,Button还是复杂的LinearLayout和ListView,它们的共同基类都是ViewView是一种界面层的控件的一种抽象,它代表了一个控件,除了View还有ViewGroup,从名字来看ViewGroup可以翻译为控件组,即一组View;在Android中,View...

weixin_42520132的博客 648

android View详解View的刷新流程源码解析

View.invalidate->ViewGroup.invalidateChild->ViewGroup.invalidateChild->……调用流程是View.requestLayout->ViewGroup.requestLayout->ViewGroup.requestLayout->……内容变化但是大小不变化会触发该方法,该方法在硬件加速打开的时候不会出现崩溃,不会进行线程检查。在开启硬件加速的情况下,View的大小未改变,之改变内存,是不会进行线程检查的。

luck_xiang的博客 837

android View 详解

android.View.View(View)类是以矩形的方式显示在屏幕上,View是用户界面控件的基础。View的继承层次关系如下图: 可以看到所有的界面控件都是View的子类。简单证实一下,每当你用findViewByIds(R.id.xx)时总要将其强转,因为该方法返回的是一个View实例,有木有!!!其中不得不提View的subClass ViewGroup。Android系统

第四维空间的专栏 4万+

android View详解

Android中的View类代表用户界面中基本的构建块。一个View在屏幕中占据一个矩形区域、并且负责绘制和事件处理。View是所有widgets的基础类,widgets是我们通常用于创建和用户交互的组件,比如按钮、文本输入框等等。子类ViewGroup是所有布局(layout)的基础类。layout是一个不看见的容器,里面堆放着其他的view或者ViewGroup,并且设置他们的布局属性。 所...

challenge51all的专栏 1万+

安卓自定义View详解

安卓自定义View 知识点:1.ViewRoot和DecorView2.MeasureSpec3.measure layout draw4. 定义View ViewRoot和DecorView ViewRoot和DecorView ViewRoot和Decor

YanRu的专栏 465

安卓自定义View进阶-事件分发机制详解Android高级工程师进阶学习】

A: 我们知道 View 可以注册很多事件监听器,例如:单击事件(onClick)、长按事件(onLongClick)、触摸事件(onTouch),并且View自身也有 onTouchEvent 方法,那么问题来了,这么多与事件相关的方法应该由谁管理?单击事件(onClickListener) 需要两个两个事件(ACTION_DOWN 和 ACTION_UP )才能触发,如果先分配给onClick判断,等它判断完,用户手指已经离开屏幕,黄花菜都凉了,定然造成 View 无法响应其他事件,应该最后调用。

2401_84007049的博客 864

安卓自定义View进阶-事件分发机制详解(1)Android开发揭秘

最后这里放上我这段时间复习的资料,这个资料也是偶然一位朋友分享给我的,里面包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。还有高级架构技术进阶脑图、高级进阶架构资料帮助大家学习提升进阶,也可以分享给身边好友一起学习。一起互勉~[外链图片转存中…(img-dLkETvLc-1711864201348)]一起互勉~本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录。

m0_62289824的博客 609

android 左右滚动条,小程序scroll-view安卓机隐藏横向滚动条的实现详解

一、实践踩坑项目使用mpvue开发1.使用flex布局// html大概长这样 // css相应就大概长这样.worth-wraper{margin-top: 60rpx;height: 560rpx;box-sizing: border-box;display: flex;width: 750rpx;overflow: hidden;font-size: 28rpx;color: #7a7...

weixin_29840475的博客 489

android View 各种属性详解

Android.View.View(View)类是以矩形的方式显示在屏幕上,View是用户界面控件的基础。View的继承层次关系如下图: 可以看到所有的界面控件都是View的子类。简单证实一下,每当你用findViewByIds(R.id.xx)时总要将其强转,因为该方法返回的是一个View实例,有木有!!!其中不得不提View的subClass ViewGroup。Android系统

a15838319826的博客 3267

智能制造-Bosch 力士乐 BS350-V2.700

智能制造-Bosch 力士乐 控制器连接工具

上一篇: 从零学习Kotlin之流程控制
下一篇: 从零学习Kotlin之数组和集合
mrkyee
博客等级 码龄9年 16粉丝 50原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值