继承View需要走的流程是:

            1.构造实例化, public ChildView(Context context, @Nullable AttributeSet attrs)

            2.测量自身的高和宽onMeasure-->setMeasuredDimension(宽,高)

            3.onDraw绘制,需要X轴,Y轴

继承ViewGroup需要走的流程是:

            1.构造实例化, public ChildView(Context context, @Nullable AttributeSet attrs)

            2.onMeasure测量子控件的高和宽,子控件.measure(宽,高),而自己的高和宽交给父控件去测量,因为我是父控件的子控件

            3.onLayout给子控件排版指定位置

布局文件,指定自定义类:

<!-- 继承View 与 继承ViewGroup的初步理解 -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myswitch="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="400dp"
android:layout_height="500dp"> <!-- 爷爷类,爷爷类有一个孩子(爸爸类) -->
<custom.view.upgrade.view_viewgroup_theory.GrandpaViewGroup
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#3300cc"
android:layout_centerInParent="true"
> <!--
虽然android:layout_centerInParent="true"属性可以去居中
但这是Android RelativeLayout 对爷爷类进行了居中的排版固定位置处理
--> <!-- 爸爸类,爸爸类有一个孩子(孩子类) -->
<custom.view.upgrade.view_viewgroup_theory.FatherViewGroup
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#00ccff"> <!-- 孩子类目前不包含孩子 -->
<custom.view.upgrade.view_viewgroup_theory.ChildView
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#cc3300"/> </custom.view.upgrade.view_viewgroup_theory.FatherViewGroup> </custom.view.upgrade.view_viewgroup_theory.GrandpaViewGroup> </RelativeLayout>

爷爷类,GrandpaViewGroup:

package custom.view.upgrade.view_viewgroup_theory;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup; /**
* 爷爷类,爷爷类有自己的孩子(爸爸类) ----> 爸爸类有自己的孩子(孩子类)
*/
public class GrandpaViewGroup extends ViewGroup { private static final String TAG = GrandpaViewGroup.class.getSimpleName(); /**
* 此两个参数的构造方法,用于在xml布局指定初始化,并传入xml中的所有属性
* @param context
* @param attrs
*/
public GrandpaViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
} // 爸爸类
private View fatherViewGroup; /**
* 当xml布局完成加载后,调用此方法
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 获取子控件(爸爸类)
fatherViewGroup = getChildAt(0);
} /**
* 由于当前是ViewGroup所以测量子控件的宽和高
* ,如果当前是View就是此类自己的高和宽
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 测量子控件(爸爸类)的宽和高
// 宽和高就是 爸爸类在xml布局中设置的值
fatherViewGroup.measure(fatherViewGroup.getLayoutParams().width, fatherViewGroup.getLayoutParams().height); // 想获取测量后子控件(爸爸类)的高和宽,是无法获取到的,因为子控件(爸爸类)是ViewGroup,拿到测量后的高和宽需要 View-->setMeasuredDimension()
// 测试下:子控件(爸爸类)的高和宽
Log.d(TAG, "fatherViewGroup.getMeasuredWidth():" + fatherViewGroup.getMeasuredWidth() +
" fatherViewGroup.getMeasuredHeight():" + fatherViewGroup.getMeasuredHeight());
} /**
* 排版 指定位置,只给子控件指定位置的
* @param changed 当发生改变
* @param l 左边线距离左边距离,注意:值是由父控件Layout后,处理了逻辑后传递过来的
* @param t 上边线距离上边距离,注意:值是由父控件Layout后,处理了逻辑后传递过来的
* @param r 右边线距离左边距离,注意:值是由父控件Layout后,处理了逻辑后传递过来的
* @param b 底边线距离上边距离,注意:值是由父控件Layout后,处理了逻辑后传递过来的
*
* 父控件必须排版了layout此类的位置,此onLayout方法才会执行,否则不执行
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 测试下:获取自身当前GrandpaViewGroup测量后的宽和高
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
Log.d(TAG, "measuredWidth:" + measuredWidth + " measuredHeight:" + measuredHeight); // 给子控件(爸爸类)指定位置
// Y轴与X轴移动计算一样,X计算:移动X轴方向,得到自身(GrandpaViewGroup爷爷类)宽度的一半 减 子控件(爸爸类)的一半就居中了
int fatherL = (measuredWidth / 2) - (fatherViewGroup.getLayoutParams().width / 2);
int fatherT = (measuredHeight / 2) - (fatherViewGroup.getLayoutParams().height / 2); // L位置增加了,R位置也需要增加
int fatherR = fatherViewGroup.getLayoutParams().width + fatherL;
int fatherB = fatherViewGroup.getLayoutParams().height + fatherT;
fatherViewGroup.layout(fatherL, fatherT, fatherR, fatherB);
} /**
* 为什么继承了ViewGroup就不需要onDraw绘制了,因为绘制都是在View中处理
* 继承了ViewGroup需要做好测量-->排版固定位置就好了,绘制是交给View去处理
*/
}

爸爸类,FatherViewGroup:

package custom.view.upgrade.view_viewgroup_theory;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup; /**
* 爸爸类,爸爸类有自己的孩子
*/
public class FatherViewGroup extends ViewGroup { private static final String TAG = FatherViewGroup.class.getSimpleName(); /**
* 此两个参数的构造方法,用于在xml布局指定初始化,并传入xml中的所有属性
* @param context
* @param attrs
*/
public FatherViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
} // 子控件(孩子类)
private View childView; /**
* 当xml布局完成加载后,调用此方法
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate(); childView = getChildAt(0);
} private int w;
private int h; /**
* 测量子控件(孩子类)的高和宽
* @param widthMeasureSpec 可以转变为模式,也可以转变为父类给当前自己传递过来的宽
* @param heightMeasureSpec 可以转变为模式,也可以转变为父类给当前自己传递过来的高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 可以获取模式
MeasureSpec.getMode(widthMeasureSpec);
MeasureSpec.getMode(heightMeasureSpec); /**
* 可以获取父类(爷爷类)在测量方法--->
* fatherViewGroup.measure(fatherViewGroup.getLayoutParams()
* .width, fatherViewGroup.getLayoutParams().height);
* 传递过来的高和宽
*/
w = MeasureSpec.getSize(widthMeasureSpec);
h = MeasureSpec.getSize(heightMeasureSpec);
Log.d(TAG, " w:" + w + " h:" + h); // 开始测量子控件(孩子类)
// 宽高都是孩子类在xml布局设置的宽高
childView.measure(childView.getLayoutParams().width, childView.getLayoutParams().height); // 测试下:子控件(孩子类)的高和宽
/**
* 注意:为什么在这里又可以获取到子控件的宽和高呢?
* 因为子控件是View 并且这个View在测量方法中执行了 setMeasuredDimension(w, h);
*/
Log.d(TAG, "childView.getMeasuredWidth():" + childView.getMeasuredWidth() +
" childView.getMeasuredHeight():" + childView.getMeasuredHeight());
} /**
* 排版 指定位置,只给子控件指定位置的
* @param changed 当发生改变
* @param l 左边线距离左边距离
* @param t 上边线距离上边距离
* @param r 右边线距离左边距离
* @param b 底边线距离上边距离
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 测试下:获取自身当前FatherViewGroup测量后的宽和高
// 注意:在这里无法获取,还不知道是什么原因!!!,
// 爷爷类可以获取到是因为爷爷类的父类控件是系统的RelativeLayout
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
Log.d(TAG, "爸爸类 >>> measuredWidth:" + measuredWidth + " measuredHeight:" + measuredHeight); // 给子控件(爸爸类)指定位置
// Y轴与X轴移动计算一样,X计算:移动X轴方向,得到自身(FatherViewGroup爸爸类)宽度的一半 减 子控件(孩子类)的一本就居中了
int childL = (w / 2) - (childView.getMeasuredWidth() / 2);
int childT = (h / 2) - (childView.getMeasuredHeight() / 2); // L位置增加了,R位置也需要增加
int childR = childView.getMeasuredWidth() + childL;
int childB = childView.getMeasuredHeight() + childT; childView.layout(childL, childT, childR, childB);
} /**
* 为什么继承了ViewGroup就不需要onDraw绘制了,因为绘制都是在View中处理
* 继承了ViewGroup需要做好测量-->排版固定位置就好了,绘制是交给View去处理
*/
}

孩子类,ChildView:

package custom.view.upgrade.view_viewgroup_theory;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View; /**
* 孩子类,孩子类暂时还没有自己的孩子,所有是继承View
*/
public class ChildView extends View { private static final String CONTEXT = "child"; // 创建画笔把文字画到画布中去
private Paint mPaint; private Rect rect; /**
* 此两个参数的构造方法,用于在xml布局指定初始化,并传入xml中的所有属性
* @param context
* @param attrs
*/
public ChildView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs); mPaint = new Paint();
// 画笔防锯齿
mPaint.setAntiAlias(true);
// 画笔白色
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(40); rect = new Rect();
} /**
* 此高宽是父控件(爸爸类)传递过来的高和宽
*/
private int w;
private int h; @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); w = MeasureSpec.getSize(widthMeasureSpec);
h = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(w, h);
} /**
* 绘制的方法
* @param canvas 画布
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // 拿到自身宽度的一半 减 文字宽度的一半 mPaint.getTextBounds(CONTEXT, 0, CONTEXT.length(), rect); int x = (w / 2) - (rect.width() / 2);
int y = (h / 2) - (rect.height() / 2) + rect.height();
canvas.drawText(CONTEXT, x, y , mPaint);
}
}

效果图:

Android-自定义控件-继承View与ViewGroup的初步理解的更多相关文章

  1. Android 中的View与ViewGroup

    Android重点知识--View和ViewGroup与自定义控件 作者:丁明祥 邮箱:2780087178@qq.com 一.基础 ViewGroup 参考资料: Android 手把手教您自定义V ...

  2. Android精通:View与ViewGroup,LinearLayout线性布局,RelativeLayout相对布局,ListView列表组件

    UI的描述 对于Android应用程序中,所有用户界面元素都是由View和ViewGroup对象构建的.View是绘制在屏幕上能与用户进行交互的一个对象.而对于ViewGroup来说,则是一个用于存放 ...

  3. Android单独继承View类来实现自定义控件

    一个单独继承view类来实现自定义控件,在该方法中,需要重写ondraw方法来绘制自己所需要的控件,下面也以一个简单的例子来说明如何实现自定义控件.该方法可以实现所需要的所有的自定义控件. 属性文件中 ...

  4. Android界面的View以及ViewGroup的区别

    因为这个问题会经常成为面试的热点,所以我们来谈谈View以及ViewGroup的区别. 先看看View及ViewGroup类关系    Android View和ViewGroup从组成架构上看,似乎 ...

  5. Android之UI View与ViewGroup

    1.基本概念 View:所有可视化控件的父类,Android App屏幕上用户可以交互的对象(例如 按钮 下拉框 文本框等). ViewGroup:View的子类,存放View和ViewGroup对象 ...

  6. android自定义控件(四) View中的方法

    onFinishInflate() 当View中所有的子控件 均被映射成xml后触发 onMeasure(int, int) 确定所有子元素的大小 onLayout(boolean, int, int ...

  7. Android View和ViewGroup

    View和ViewGroup Android的UI界面都是由View和ViewGroup及其派生类组合而成的. 其中,View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也 ...

  8. android自定义控件一站式入门

    自定义控件 Android系统提供了一系列UI相关的类来帮助我们构造app的界面,以及完成交互的处理. 一般的,所有可以在窗口中被展示的UI对象类型,最终都是继承自View的类,这包括展示最终内容的非 ...

  9. Android自定义控件1--自定义控件介绍

    Android控件基本介绍 Android本身提供了很多控件比如我们常用的有文本控件TextView和EditText:按钮控件Button和ImageButton状态开关按钮ToggleButton ...

随机推荐

  1. 黄聪:VS2010启动程序提示文件加载 使用 简体中文(GB2312)编码加载文件解决办法

    vs2010 错误提示框:文件加载 使用 简体中文(GB2312)编码加载文件C:\Users\Administrator\AppData\Local\Temp\nxhgjasi.5au \Temp\ ...

  2. bzoj4558: [JLoi2016]方

    Description 上帝说,不要圆,要方,于是便有了这道题.由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形 上帝把我们派到了一个有N行M列的方格图上,图上一共有(N+1)×(M+1) ...

  3. zoj-3410-Layton's Escape

    /* ZOJ Problem Set - 3410Layton's Escape ----------------------------------------------------------- ...

  4. 测试Linux端口的连通性的四种方法

    Linux系统有时候需要测试某个端口的连通性,用户可以参考如下方法来测试.   方法一.telnet法 telnet为用户提供了在本地计算机上完成远程主机工作的能力,因此可以通过telnet来测试端口 ...

  5. CentOS7 安装svn

    1 yum install subversion 2 运行 svn --version 报错 svn: error while loading shared libraries: libaprutil ...

  6. mysql java.sql.SQLException: Can't call commit when autocommit=true

    java.sql.SQLException: Can't call commit when autocommit=true at com.mysql.jdbc.SQLError.createSQLEx ...

  7. vs2015 新特性

    vs2015 新特性 自动属性的增强 http://www.kwstu.com/ArticleView/manong_201411200854239378

  8. oracle创建新数据库

    oracle创建新数据库 look here http://www.cnblogs.com/phoenixzq/p/3510854.html windows start menu>Oracle& ...

  9. Spring IO Platform介绍

    为什么要用Spring IO Platform 今天无意间看到了一个关键词:"Spring IO Platform",第一直觉是不是有关于IO方面的框架或者包呢,查了一下,居然是为 ...

  10. Struts2 学习记录-1--Struts2中的配置文件

    目录 1. web.xml 2. struts.xml 3. struts.properties文件 4.注解式开发 5.与Spring框架集成的配置 主要涉及3个配置文件:web.xml.strut ...