乐虎游戏|乐虎国际登录|欢迎你

View 的可知性检查仍然为能够如此~

日期:2020-03-13编辑作者:计算机资讯

在Android开发中,我们常常会对View的可视性visiblity进行操作或者检查。如网络请求数据,根据返回的数据结果控制相应View可见或不可见,或者判断某个View是否在屏幕中可见,不可见时给予用户相应提示信息等。在ListView、RecyclerView、ScrollView里我们可能会比较经常做这些事。比如在下面的ScrollView中:

前言:昨天项目迭代增加一个功能,对一个View在用户看到的时候增加动画,该View是在list作为footerView添加进去的,需要判断一个view对于用户是否可见,也自己实践了一下,总结总结。

引言

Canvas相信大家都不会陌生,虽然看来很简单,也知道各种API的用法和作用,但是很多人觉得自定义View很难,很大一部分原因就是对于Canvas不够熟悉,或许看教材和视频只是教你要移动translate、rotate、save、restore等,很少告知你为什么这样做,导致你只能照敲不能灵活应用。所以知其然更要知其所以然,授人以鱼不如授人以渔,这篇文章我争取把Android 2D绘画的一些相关知识点总结出来。

图片 1

网上查到的方法,有一个提到重写view中“onWindowVisibilityChanged”的方法,来判断是否可见,具体如下:

一、Android系统坐标系

把Android绘画当成现实中的画家作画,Canvas自然就是画家笔下的画板,而画家自然就是Android系统本身,在现实生活中画家可以自主决定从哪个点开始起笔,又延伸到哪点,而在机器世界里都是需要去一系列的逻辑计算的,因而坐标系应运而生,在Android中主要有两大坐标系:Android坐标系和视图坐标系

这里写图片描述

四种方法获取的结果如下:

@Override

protected voidonWindowVisibilityChanged(intvisibility) {

super.onWindowVisibilityChanged(visibility);

if(visibility == View.VISIBLE){

//开始某些任务

if(!isCover()){

if(onViewVisibilityListener!=null){

onViewVisibilityListener.onVisible();

}

}

}else if(visibility ==INVISIBLE|| visibility ==GONE){

//停止某些任务

if(onViewVisibilityListener!=null){

onViewVisibilityListener.onInVisible();

}

}

}

1、Android坐标系

Android坐标系可以看成是物理存在的坐标系,也可以理解为绝对坐标,以屏幕为参照物,就是以屏幕的左上角是坐标系统原点(0,0),原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向。比如系统的getLocationOnScreen(int[] location)实际上获取Android坐标系中位置(即该View左上角在Android坐标系中的坐标),还有getRawX()、getRawY()获取的坐标也是Android坐标系的坐标。

View5.getVisibility() = View.VISIBLE;View5.isShown() = true; View5.getGlobalVisibleRect() = false;View5.getLocalVisibleRect() = false;

ps:吐槽一下简书这个编辑器对于代码的规范化真的和屎一样,当然可能我自己没学会掌握~

2、视图坐标系

视图坐标系是相对坐标系,是以父视图为参照物,以父视图的左上角为坐标原点(0,0),原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向,getX()、getY()就是获取视图坐标系下的坐标。

为什么有这样的结果呢?四种方法的具体的区别是什么?getGlobalVisibleRect和getLocalVisibleRect具体怎么用呢?先说下几种方法的具体区别。

大写的BUT,据我测试得出,该方法在第一次加载View的时候就触发了(visibility== View.VISIBLE),然后随着滑动滑出滑入屏幕丫都没有再次触发,网上查阅的对于该方法的解释是:

3、两种坐标系在Android的应用

这里写图片描述

1.View.getVisibility()

这是常用的也是最基本的检查View可见性的方法,这个方法的返回值有View.VISIBLE、View.INVISIBLE(不可见但占着原来的空间)和View.GONE( 不可见且不占原来的空间)。如果这个方法返回的是View.INVISIBLE或者View.GONE,那么这个View肯定是对用户不可见的。

onWindowVisibilityChanged(int) 当窗口中包含的可见的view发生变化时触发

3.1、子View获取自身尺寸信息

  • getHeight():获取View自身高度
  • getWidth():获取View自身宽度
2.View.isShown()

这个方法和View.getVisibility()作用类似,重要的区别就是:

  • getVisibility()返回的是int值,isShown()返回的是boolean值
  • View.isShown()会对View的所有父类调用getVisibility方法
/** * Returns the visibility of this view and all of its ancestors * * @return True if this view and all of its ancestors are {@link #VISIBLE} */public boolean isShown() { View current = this; //noinspection ConstantConditions do { if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { return false; } ViewParent parent = current.mParent; if (parent == null) { return false; // We are not attached to the view root } if (!(parent instanceof View)) { return true; } current =  parent; } while (current != null); return false;}

经过测试得出,该方法在在第一次加载绘制view时会被调用,然后在view被销毁或者挂起时再被调用(如从当前界面跳转到其他activity时),详细查阅以及跟踪了其源代码发现,调用该方法的地方主要在

3.2、子View获取自身坐标信息

子View的存在是依附于父View的,所以用的是相对坐标来表示,如下方法可以获得子View到其父View(ViewGroup)的距离:

  • getLeft():获取子View自身左边到其父View左边的距离
  • getTop():获取子View自身顶边到其父View顶边的距离
  • getRight():获取子View自身右边到其父View左边的距离
  • getBottom():获取子View自身底边到其父View顶边的距离
  • getMargingXxxx:获取子View的边框距离父ViewGroup边框的距离即外边距,Xxxx代表Left、Right、Top、Bootom。
    • getPaddingXxxx:获取子View内部的内容的边框距离子View的边框的距离即内边距,Xxxx代表Left、Right、Top、Bootom。

由源码中注释可以知道,这个方法递归地去检查这个View以及它的parentView的Visibility属性是不是等于View.VISIBLE,这样就对这个View的所有parentView做了一个检查。另外这个方法还在递归的检查过程中,检查了parentView

null,也就是说所有的parentView都不能为null。否则就说明这个View根本没有被addView过(比如创建界面UI时,可能会先new一个View,然后根据条件动态地把它add带一个ViewGroup中),那肯定是不可能对用户可见的。

图片 2

3.3、获取MotionEvent中对应坐标信息

无论是View还是ViewGroup,Touch事件都会经由onTouchEvent(MotionEvent event)方法来处理,通过MotionEvent实例event可以获取相关坐标信息。

  • getX():获取Touch事件当前触摸点距离控件左边的距离,即视图坐标下对应的X轴的值
  • getY():获取Touch事件距离控件顶边的距离,即视图坐标系下对应的Y轴的值
  • getRawX():获取Touch事件距离整个屏幕左边距离,即绝对坐标系下对应的X轴的值
  • getRawY():获取Touch事件距离整个屏幕顶边的的距离,即绝对坐标系下对应的Y轴的值
3.View.getGlobalVisibleRect()

顾名思义,这个方法会返回一个View是否可见的boolean值,同时还会将该View的可见区域left,top,right,bottom值保存在一个rect对象中,具体使用方法如下:

Rect globalRect = new Rect();boolean visibile = view5.getGlobalVisibleRect(globalRect);

getGlobalVisibleRect最后调用的是getGlobalVisibleRect(Rect r, Point globalOffset)方法,看下该方法的注释:

/** * If some part of this view is not clipped by any of its parents, then * return that area in r in global  coordinates. To convert r to local * coordinates (without taking possible View rotations into account), offset * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). * If the view is completely clipped or translated out, return false. * * @param r If true is returned, r holds the global coordinates of the * visible portion of this view. * @param globalOffset If true is returned, globalOffset holds the dx,dy * between this view and its root. globalOffet may be null. * @return true if r is non-empty (i.e. part of the view is visible at the * root level. */

由以上注释可以知道,当这个View只要有一部分仍然在屏幕中(没有被父View遮挡,即not clipped by any of its parents),那么将把没有被遮挡的那部分区域保存在rect对象中返回,且返回visibility为true。此时的rect是以手机屏幕作为坐标系(即global coordinates),也就是原点是屏幕左上角;如果它全部被父View遮挡住了或者本身就是不可见的,返回的visibility就为false,rect中的值为0。

销毁时

3.4、获取view在屏幕中的位置

如果在Activity的OnCreate()事件调用这些方法,那么输出那些参数全为0,必须要等UI控件都加载完了才能获取到。

  • getLocalVisibleRect() :返回一个填充的Rect对象, 所有的View都是以一块矩形内存空间存在的

  • getGlobalVisibleRect() :获取Android坐标系的一个视图区域, 返回一个填充的Rect对象且该Rect是基于总整个屏幕的

  • getLocationOnScreen :计算该视图在Android坐标系中的x,y值,获取在当前屏幕内的绝对坐标
    (这个值是要从屏幕顶端算起,当然包括了通知栏和状态栏的高度)

  • getLocationInWindow ,计算该视图在它所在的widnow的坐标x,y值,获取在整个window的绝对坐标

    int[] location = new int[2];
    view.getLocationOnScreen(location);
    int x = location[0];
    int y = location[1];
4.View.getLocalVisibleRect()

这个方法和getGlobalVisibleRect有些类似,也可以拿到这个View在屏幕的可见区域的坐标,唯一的区别getLocalVisibleRect获得的rect坐标系的原点是View自己的左上角,而不是屏幕左上角。其也会调用getGlobalVisibleRect()方法:

public final boolean getLocalVisibleRect { final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); if (getGlobalVisibleRect(r, offset)) { r.offset(-offset.x, -offset.y); // make r local return true; } return false;}

由以上源码可以看到,getLocalVisibleRect()会先获取View的offset point(相对屏幕或者ParentView的偏移坐标),然后再去调用getGlobalVisibleRect(Rect r, Point globalOffset)方法来获取可见区域,最后再把得到的GlobalVisibleRect和Offset坐标做一个加减法,转换坐标系原点。使用方法如下:

Rect localRect = new Rect();boolean visibile = view5.getLocalVisibleRect(localRect);

图片 3

二、Paint

方法 说明
图形绘制相关
setARGB(int a,int r,int g,int b); 用于绘制图形,设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
setAlpha(int a) 设置绘制图形的透明度
setColor(int color) 设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色
setAntiAlias(boolean aa) 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢
setDither(boolean dither) 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
setFilterBitmap(boolean filter) 如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度,本设置项依赖于dither和xfermode的设置
setMaskFilter(MaskFilter maskfilter) 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等
setColorFilter(ColorFilter colorfilter) 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
setPathEffect(PathEffect effect) 设置绘制路径的效果,如点画线
** setShader(Shader shader)** 设置图像效果,使用Shader可以绘制出各种渐变效果
setShadowLayer(float radius ,float dx,float dy,int color) 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色
setStyle(Paint.Style style) 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE
setStrokeCap(Paint.Cap cap) 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式Cap.ROUND,或方形样式Cap.SQUARE
setSrokeJoin(Paint.Join join) 设置绘制时各图形的结合方式,如平滑效果等
setStrokeWidth(float width) 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
setXfermode(Xfermode xfermode) 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
文本绘制相关
setFakeBoldText(boolean fakeBoldText) 模拟实现粗体文字,但设置在小字体上效果会非常差
setSubpixelText(boolean subpixelText) 设置该项为true,将有助于文本增强在LCD屏幕上的显示效果
setTextAlign(Paint.Align align) 设置绘制文字的对齐方向
setTextScaleX(float scaleX) 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果
setTextSize(float textSize) 设置绘制文字的字号大小
setTextSkewX(float skewX) 设置斜体文字,skewX为倾斜弧度
setTypeface(Typeface typeface) 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
setUnderlineText(boolean underlineText) 设置带有下划线的文字效果
setStrikeThruText(boolean strikeThruText) 设置带有删除线的效果

Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色, 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。

方法 说明
图形绘制相关
setARGB(int a,int r,int g,int b); 用于绘制图形,设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
setAlpha(int a) 设置绘制图形的透明度
setColor(int color) 设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色
setAntiAlias(boolean aa) 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢
setDither(boolean dither) 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
setFilterBitmap(boolean filter) 如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度,本设置项依赖于dither和xfermode的设置
setMaskFilter(MaskFilter maskfilter) 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等
setColorFilter(ColorFilter colorfilter) 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
setPathEffect(PathEffect effect) 设置绘制路径的效果,如点画线
** setShader(Shader shader)** 设置图像效果,使用Shader可以绘制出各种渐变效果
setShadowLayer(float radius ,float dx,float dy,int color) 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色
setStyle(Paint.Style style) 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE
setStrokeCap(Paint.Cap cap) 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式Cap.ROUND,或方形样式Cap.SQUARE
setSrokeJoin(Paint.Join join) 设置绘制时各图形的结合方式,如平滑效果等
setStrokeWidth(float width) 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
setXfermode(Xfermode xfermode) 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
文本绘制相关
setFakeBoldText(boolean fakeBoldText) 模拟实现粗体文字,但设置在小字体上效果会非常差
setSubpixelText(boolean subpixelText) 设置该项为true,将有助于文本增强在LCD屏幕上的显示效果
setTextAlign(Paint.Align align) 设置绘制文字的对齐方向
setTextScaleX(float scaleX) 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果
setTextSize(float textSize) 设置绘制文字的字号大小
setTextSkewX(float skewX) 设置斜体文字,skewX为倾斜弧度
setTypeface(Typeface typeface) 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
setUnderlineText(boolean underlineText) 设置带有下划线的文字效果
setStrikeThruText(boolean strikeThruText) 设置带有删除线的效果
* 5.getGlobalVisibleRect() VS getLocalVisibleRect()*

回到最开始的问题,四种方法获取view5的visibility结果应该很好理解了,那getGlobalVisibleRect()和getLocalVisibleRect()中获取出的rect值具体区别在哪儿?如下图,假设屏幕大小为1080x1920,以ScrollView为Parent View,在ScrollView的onScrollChanged()中对view1,view3和view5的可见性进行判断:

图片 4

代码比较简单,直接就看debug结果吧,如下:

图片 5由以上结果可以看出getGlobalVisibleRect()和getLocalVisibleRect()对View的可见性visibility判断结果相同,只是获取出的rect值有所区别:

  • 当View在屏幕中全部可见时,根据上面的介绍知,getLocalVisibleRect()的原点是自己的左上角,所以当View的左上角在屏幕中时,获取的rect左上角坐标一定为,右下角为(View.getWidth, View.getHeight),而getGlobalVisibleRect()的原点是屏幕左上角,获取出的rect值是与getLocalVisibleRect()左上角不为;
  • 当View在屏幕中部分可见时,getLocalVisibleRect()获取的rect值左上角不为,但此时也与getGlobalVisibleRect()获取值不同;
  • View在屏幕中全部不可见时,两者的visibility都为false,且两者获取的rect值相同。这是为什么呢?由源码可以知道,getLocalVisibleRect()最终调用的是getGlobalVisibleRect()方法,并会减去View自身的便偏移坐标offset point,但只有当View可见时才会减去这个偏移坐标,要是不可见就直接返回了,所以此时两者获取出的rect值是相同的。

加载时

三、Canvas绘图

本文由乐虎游戏发布于计算机资讯,转载请注明出处:View 的可知性检查仍然为能够如此~

关键词:

Maven pom 详明

Resources.../Resources Maven 属性默认只有在 pom.xml 中才会被解析,对于放在 src/main/resources/ 目录下的文件,maven 是需要通过...

详细>>

Android Support Library介绍

更多原创文章和优质资源请关注公众号: ***转载、引用请标明出处*** 本文出自zhh_happig的简书博客   open_dev   网上对...

详细>>

计算机:RxJava2.0(一)

Outline 特此声明:本文为转载文章!尊重原创的劳动果实,严禁剽窃 本文转载于:http://www.jianshu.com/p/464fa025229e 出自于...

详细>>

Rxjava2~zip~学渣带你扣rxjava2~ map操作符到底干了什么

prestatic ObservableString sampleObservable() {returnObservable.defer(new CallableObservableSource? extendsString() {@Overridepublic ObservableSource? ...

详细>>