自定义View(一)、基础概念和知识点

1,528 阅读8分钟

自定义View(一)、基础概念和知识点

接下来一段时间我们将整理一系列自定义View文章,由浅到难,磨刀不误砍柴工,在真正开始之前,我们还是对自定义View的知识点有一定的了解和补充。

一、坐标系

为什么坐标系要提出来讲,因为在Android中和我们传统的坐标系有一定的区别,我们需要做区分。

  • 数学坐标系:

右为X轴的正方向,上为Y轴的正方向,同理,数学坐标系中角度也是逆时针为正方向,如下图:

  • 屏幕坐标系

Android中屏幕的坐标系定义是以左上角为起点,右边为X轴正方向,下方为Y轴正方向,如下图:

对应的角度方向,也是顺时针为正方向

贴上一个屏幕,大概就是下面这样

二、View的坐标系

View的坐标系统是相对于父控件而言的
通常有以下几个方法,

getTop()
获取View左上角距父View顶部的距离

getLeft()
获取View左上角距父View左侧的距离

getBottom()
获取View右下角距父View顶部的距离

getRight()
获取View右下角距父View左侧的距离

怎么理解呢,我们直接通过Demo来验证,先写一个布局文件如下:

activity_ui_custom_location.xml

 1<?xml version="1.0" encoding="utf-8"?>
2<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3    android:layout_width="match_parent"
4    android:layout_height="match_parent"
5    android:gravity="center">
6
7    <LinearLayout
8        android:id="@+id/ll_view"
9        android:layout_width="300dp"
10        android:layout_height="300dp"
11        android:background="@color/colorAccent">
12
13        <View
14            android:id="@+id/view"
15            android:layout_width="100dp"
16            android:layout_height="100dp"
17            android:background="@color/colorPrimary" />
18    </LinearLayout>
19</RelativeLayout>

上面的xml布局文件预览如下:

通过上面的xml文件我们可以分析出来,B(View)视图的父View是A(LinearLayout),而A(LinearLayout)的父布局又是C(RelativeLayout)

我们现在分别来获取A和B的坐标位置:

 1  View mView = findViewById(R.id.view);
2        LinearLayout mLlView = findViewById(R.id.ll_view);
3        mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
4            @Override
5            public void onGlobalLayout() {
6                mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
7                int viewLeft = mView.getLeft();
8                int viewTop = mView.getTop();
9                int viewRight = mView.getRight();
10                int viewBottom = mView.getBottom();
11
12                LogUtil.d(TAG + "--view viewLeft=" + viewLeft);
13                LogUtil.d(TAG + "--view viewTop=" + viewTop);
14                LogUtil.d(TAG + "--view viewRight=" + viewRight);
15                LogUtil.d(TAG + "--view viewBottom=" + viewBottom);
16            }
17        });
18
19        mLlView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
20            @Override
21            public void onGlobalLayout() {
22              mLlView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
23                int llViewLeft = mLlView.getLeft();
24                int llViewTop = mLlView.getTop();
25                int llViewRight = mLlView.getRight();
26                int llViewBottom = mLlView.getBottom();
27
28                LogUtil.d(TAG + "--view llViewLeft=" + llViewLeft);
29                LogUtil.d(TAG + "--view llViewTop=" + llViewTop);
30                LogUtil.d(TAG + "--view llViewRight=" + llViewRight);
31                LogUtil.d(TAG + "--view llViewBottom=" + llViewBottom);
32            }
33        });

结果:

我们看到B(View)获取的topleft为0,由此可以推断出View获取的坐标位置是基于父布局来的,因为B的左上角刚好是其父类的左上角,所以获取数据为0。如果我们B居中,如下:

再次获取坐标位置结果如下:

分析结果能得出如下结论:

三.MotionEvent中 get 和 getRaw 的区别

我们同样先通过Demo来得出结论,我们直接拿上面的demo进行演示,

 1mView.setOnTouchListener(new View.OnTouchListener() {
2            @Override
3            public boolean onTouch(View v, MotionEvent event) {
4                float getX = event.getX();
5                float getRawX = event.getRawX();
6
7                float getY = event.getY();
8                float getRawY = event.getRawY();
9
10                LogUtil.d(TAG + "--setOnTouchListener  getX=" + getX + ",getRawX=" + getRawX);
11                LogUtil.d(TAG + "--setOnTouchListener  getY=" + getY + ",getRawY=" + getRawY);
12                return false;
13            }
14        });

我们尽量的点击视图B的左上角位置,得到如下结果:

我们可以看到getXgetY 的值趋近于零(手指点击最左上角得到的结果应该是0,0)
getRawXgetRawY 的值对比上面的结果,肯定不是相对于父类A的,而是相对于屏幕的坐标位置。

基于以上结果,大致得出以下结论:

实际坐标出发点是同一点,为了区分黄线分别右移和下移了一点,图比较粗糙,清楚就好。

四、Android中角度和弧度

在后续的自定义View中,一些复杂的图形需要各种数学上的计算,简单举个例子,我们在自定义圆形进度条或者自定义一个钟表的时候,就涉及到角度和弧度的概念,所以我们提前对Android中的角度和弧度有一个认识。

首先看看,角度和弧度在圆上如何表示:

角度

弧度

由上面两个图可以得出角度和弧度的定义:

名称 定义
角度 两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆周长的360分之一时,两条射线的夹角的大小为1度.
弧度 两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆的半径时,两条射线的夹角大小为1弧度.

为什么对角的描述有角度和弧度两种,因为二者进制不同,角度是60进制,而弧度是十进制,在自定义View计算的时候可以要根据不同的数值进行转换。

4.1、角度和弧度的换算方式

圆一周角度为360°,弧度为2π

所以 360° = 2π --------------------------> 180° = π

  • 1° = π/180
  • 1弧度 = 180/π

五、颜色

5.1、简单颜色介绍

Android中支持的颜色模式

颜色模式 备注
ARGB8888 四通道高精度(32位)
ARGB4444 四通道低精度(16位)
RGB565 屏幕默认模式(16位)
Alpha8 仅有透明通道(8位)

字母表示通道类型,数值表示该类型用多少位二进制来表示
如ARGB8888表示有四个通道,每个对应的通道用8位二进制表示
RGB565表示三个通道,每个对应通道分别使用5、6、5位二进制表示

注意:我们常用的是ARGB8888和ARGB4444,而在所有的安卓设备屏幕上默认的模式都是RGB565,请留意这一点

以ARGB8888为例介绍颜色定义:

类型 解释 0(0x00) 255(0xff)
A(Alpha) 透明度 透明 不透明
R(Red) 红色 无色 红色
G(Green) 绿色 无色 绿色
B(Blue) 蓝色 无色 蓝色
  • 其中 A R G B 的取值范围均为0(0000 0000)- 255(1111 1111)

  • A 从0x00到0xff表示从透明到不透明。

  • RGB 从0x00到0xff表示颜色从浅到深。

我们在代码中颜色设置就可以如下定义:

总结

简单介绍了一下自定义view一些基础概念和知识点,本文感谢
自定义View,这是自定义view第一篇,后续会一步步探索,也会通过一些实战来巩固,整理也是学习过程,文章内容会尽量整的详细一些,感谢你的阅读,如果文中有错误之处,接受批评和指点。