自定义View(一)——自定义ViewGroup+简单自绘View

本文详细介绍了Android中自定义View的步骤,包括为何自定义View、自定义ViewGroup和自绘View。讲解了View的位置描述、LayoutInflater的使用、自定义属性、onDraw()和onMeasure()方法的重写,以及如何处理wrap_content和padding属性。通过实例展示了自定义TitleView和自绘数字计数器View的实现过程。
摘要由CSDN通过智能技术生成

为什么要自定义View

  1. 需求有特定风格的控件
  2. 用户交互,例如滑动TextView中的文字
  3. 嵌套布局(?)
  4. 封装常用的一组控件,例如底部导航栏

自定义View的步骤

  1. 自定义属性,attr中声明,代码中获取
  2. onMeasure():测量
  3. onLayout():布局(ViewGroup)
  4. onDraw():绘制
  5. onTouchEvent():交互
  6. onInterceptTouchEvent():拦截动作(ViewGroup)

View位置描述

在这里插入图片描述
4个顶点的位置描述分别由4个值决定:
(请记住:View的位置是相对于父控件而言的)

Top:子View上边界到父view上边界的距离
Left:子View左边界到父view左边界的距离
Bottom:子View下边距到父View上边界的距离
Right:子View右边界到父view左边界的距离

LayoutInflate

LayoutInflate主要用于加载布局,包括在Activity中调用setContentView(),方法内部其实也是用LayoutInflate来实现的。

基本用法:

  • 两句语句都可以获取到LayoutInflater的实例
//两种初始化方式
        LayoutInflater inflater = LayoutInflater.from(this);
//        LayoutInflater inflater1 = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

因为在源码里,from就是一个系统封装好的方法,里面用了context.getSystemService……
在这里插入图片描述

  • 调用他的inflate方法加载布局
  • inflate()方法一般接收两个参数,第一个参数就是要加载的布局id,第二个参数是指给该布局的外部再嵌套一层父布局,如果不需要就直接传null。
  • 这样就成功成功创建了一个布局的实例,之后再将它添加到指定的位置就可以显示出来了。
inflater.inflate(resourceId, root);

举个栗子:

  • activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_layout"
    android:orientation="vertical">
    
</LinearLayout>
  • button_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="button">

</RelativeLayout>
  • 如何通过LayoutInflater来将 button_layout布局 添加到主布局文件的LinearLayout中呢?
  • MainActivity中
  • 用inflate()方法来加载button_layout这个布局,然后调用LinearLayout的addView()方法将它添加到LinearLayout中。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LinearLayout mainLayout = findViewById(R.id.main_layout);
        //两种初始化方式
        LayoutInflater inflater = LayoutInflater.from(this);
//        LayoutInflater inflater1 = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View buttonLayout = inflater.inflate(R.layout.button_layout, null);
        mainLayout.addView(buttonLayout);
  • 效果
    在这里插入图片描述

  • 改变button的大小

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="300dp"
    android:layout_height="100dp"
    android:text="button">

</RelativeLayout>

发现button大小并未改变。

layout_width和layout_height 其实是用于设置View在布局中的大小的,也就是View必须存在于一个布局中,这两个参数的设定才有效。这也是为什么这两个属性叫作layout_width和layout_height,而不是width和height。

所以最简单的是在Button的外面再套一个布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:layout_width="300dp"
        android:layout_height="150dp"
        android:text="button"/>

</RelativeLayout>

变大了!
在这里插入图片描述

  • 问题又来了,平时在Activity中指定布局文件的时候,最外层的那个布局是可以指定大小的呀,layout_width和layout_height都是有作用的。
  • 这主要是因为,在setContentView()方法中,Android会自动在布局文件的最外层再嵌套一个FrameLayout,所以layout_width和layout_height属性才会有效果。
  • 那么我们来证实一下吧,在MainActivity加入以下代码:
        ViewParent parent = mainLayout.getParent();
        Log.d("MainActivity", "the parent of mainLayout is" + parent);

log信息
在这里插入图片描述
可以看到,LinearLayout的父布局确实是一个FrameLayout,而这个FrameLayout就是由系统自动帮我们添加上的。

自定义ViewGroup

组合控件的意思就是,我们并不需要自己去绘制视图上显示的内容,而只是用系统原生的控件就好了,我们将几个系统原生的控件组合到一起,例如最常见的 标题栏。

  1. 新建一个view_title.xml布局文件,写我们标题栏的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_back"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:text="back"
        android:textAllCaps="false"/>

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="250dp"
        android:layout_height="50dp"
        android:text="This is title"
        android:textAllCaps=&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值