Android Studio开发学习(四)——— View与ViewGroup

一、了解认识View与ViewGroup

在Android APP中,所有的用户界面元素都是由View和ViewGroup的对象构成的。View是绘制在屏幕上的用户能与之交互的一个对象。而ViewGroup则是一个用于存放其他View(和ViewGroup)对象的布局容器。

APP的用户界面上的每一个组件都是使用View和ViewGroup对象的层次结构来构成的,比如下图。每个ViewGroup都是要给看不见的用于组织子View的容器,而它的子View可能是输入控件或者在UI上绘制了某块区域的小部件。有了层次树,就可以根据自己的需要,设计简单或者复杂的布局了(布局越简单性能越好)。

 Android里的图形界面都是由View和ViewGroup以及他们的子类构成的:View:所有可视化控件的父类,提供组件描绘和时间处理方法。 ViewGroup: View类的子类,可以拥有子控件,可以看作是容器 Android UI中的控件都是按照这种层次树的结构堆叠得,而创建UI布局的方式有两种, 自己在Java里写代码或者通过XML定义布局,后者显得更加方便和容易理解! 也是我们最常用的手段!一般很少直接用View和ViewGroup来写布局,更多的时候使用它们的子类控件或容器来构建布局。

二、了解认识自定义View和自定义ViewGroup

自定义 View 和自定义 ViewGroup 是 Android 开发中常见的两种自定义视图的方式。它们允许开发者根据自己的需求和设计来创建完全定制的界面元素。接下来详细介绍自定义View 和自定义 ViewGroup,并对它们的实现和使用进行解析。

1.自定义 View

自定义 View 是指创建一个新的 UI 控件,可以通过继承现有的 View 类(如 TextView、Button 等)或直接继承 View 类来实现。通常情况下,自定义 View 用于实现一些具体的 UI 绘制和交互逻辑,例如自定义的图表、进度条等。自定义 View 需要重写 onDraw() 方法来实现自定义的绘制逻辑,并根据需要处理触摸事件、测量逻辑等。

简单来说自定义 View 也就是指通过继承现有的 View 类,重写相关方法和实现自定义的绘制逻辑,来创建一个新的自定义视图。以下是自定义 View 的主要步骤和一些注意事项:

a.主要步骤:
  1. 创建自定义 View 类:自定义 View 需要继承 View 或 View 的子类(如 TextView、ImageView 、Button 等)。

  2. 重写 onDraw() 方法:在此方法中实现自定义的绘制逻辑,可以使用 Canvas 绘制各种图形、文字、图片等。通过重写 onDraw() 方法,可以实现自定义的界面效果

  3. 处理用户交互:根据实际需求,可以重写 onTouchEvent()onClickListener() 等方法来处理用户的触摸事件和点击事,实现交互效果。

  4. 添加自定义属性(可选):通过在 res/values/attrs.xml 文件中定义自定义属性,并在 View 构造方法中获取和处理这些属性,可以增加自定义 View 的灵活性。

  5. 重写 onMeasure() 方法(根据需要):该方法用于测量 View 的大小,可以根据实际需要设置 View 的宽度和高度。在 onMeasure() 方法中确定 View 的测量尺寸,可确保 View 在父容器中能正确显示。需要注意的是, onMeasure()  方法中需要调用  setMeasuredDimension() 来设置测量后的宽度和高度。

  6. 在布局文件中使用自定义 View:在 XML 布局文件中引用自定义 View,并设置相应的属性。

b.注意事项:
  1. 避免过度绘制:在  onDraw() 方法中尽量减少绘制操作,避免影响性能。

  2. 优化绘制操作:使用硬件加速、缓存绘制结果等方式来优化绘制效率。

  3. 处理不同屏幕密度:在绘制时考虑不同屏幕密度下的适配,避免出现拉伸或模糊的情况。

  4. 正确处理触摸事件:确保正确处理触摸事件,以实现用户与自定义 View 的交互。

  5. 测试和调试:在开发过程中进行充分的测试和调试,确保自定义 View 的功能和效果符合预期。

  6. 文档和注释:为自定义 View 添加清晰的文档和注释,方便他人理解和维护代码。

        自定义 View 提供了强大的灵活性和可定制性,可以根据具体的业务需求实现各种独特的界面效果和交互行为。自定义 View 可以用于创建复杂的图表、动画效果、自定义控件等。

c.简单示例:
        1.创建 CustomView.java 文件

        在 Android 应用开发中,通常会将自定义 View 类的代码放在一个 Java 文件中,该文件的路径可以根据项目结构进行灵活设置。一般来说,你可以在 src 目录下的相应包名路径中创建 CustomView.java 文件,其中包含自定义 View 类的代码。

例如,小编的包名是 com.example.example, app/src/main/java/com.example.example目录下创建 CustomView.java 文件,并将上面提供的 CustomView 类代码放入其中。

package com.example.example;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class CustomView extends View {
    private Paint mPaint; // 定义一个 Paint 对象
    public CustomView(Context context) {
        super(context);
        init();
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        // 初始化操作,例如设置画笔颜色、字体样式等
        // 初始化 Paint 对象
        mPaint = new Paint();
        mPaint.setColor(Color.RED); // 设置画笔颜色为红色
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 测量 View 的大小逻辑,设置自身宽度和高度
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 绘制逻辑,例如绘制一个简单的矩形
        super.onDraw(canvas);
        canvas.drawRect(50, 50, 200, 200, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 处理触摸事件的逻辑,例如点击、滑动等
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 点击事件处理
                Log.i("Bluetooth", "嘻嘻嘻点击成功");
                return true;
            case MotionEvent.ACTION_MOVE:
                // 滑动事件处理
                Toast mToast = Toast.makeText(getContext(), "哈哈滑动成功", Toast.LENGTH_SHORT);
                mToast.show(); 
                return true;
            case MotionEvent.ACTION_UP:
                // 手指抬起事件处理
                return true;
        }
        return super.onTouchEvent(event);
    }
}
        2.在布局文件(如 activity_main.xml)中添加 CustomView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal">

<!-- <com.yourpackage.CustomView  -->

    <com.example.example.CustomView
        android:id="@+id/custom_view"
        android:layout_width="match_parent"
        android:layout_height="200dp" />
</LinearLayout>
        3.在 Activity (如MainActivity)中找到 CustomView 并进行操作
package com.example.example;

import android.os.Bundle; 
import android.view.View;  
import androidx.appcompat.app.AppCompatActivity; 

public class MainActivity extends AppCompatActivity { 
    private CustomView customView; 

    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        customView = findViewById(R.id.custom_view);
        // 可以根据需要对 CustomView 进行操作,例如设置监听器
        customView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { }
        });

    } 
}  
         4.运行应用查看效果

2.自定义ViewGroup 

自定义 ViewGroup 是 Android 开发中非常有用的技术,可以帮助开发者创建自定义的布局容器,实现特定的布局结构或布局行为。

自定义 ViewGroup 是指通过继承现有的 ViewGroup 类,重写相关方法和管理子视图的布局和绘制逻辑,来创建一个新的自定义容器。下面是自定义 ViewGroup 的主要步骤和注意事项:

 a.主要步骤:
  1. 创建自定义 ViewGroup 类:自定义 ViewGroup 需要继承自 ViewGroup  或 ViewGroup 的子类(如 LinearLayout、RelativeLayout、FrameLayout 等)。

  2. 重写 onMeasure() 方法:该方法用于测量 ViewGroup 的大小和子视图的大小。在 onMeasure() 方法中需要测量和设置子视图的测量规格,并根据子视图的大小计算并设置 ViewGroup 自身的测量规格。在该方法中确定 ViewGroup 自身的尺寸以及子视图的尺寸和位置,确保子视图能正确显示在 ViewGroup 中。

  3. 重写 onLayout() 方法:在该方法中指定子视图的位置,即确定子视图在 ViewGroup 中的位置和大小。在 onLayout() 方法中需要计算每个子视图的位置和大小,并通过调用子视图的 layout() 方法来设置它们的位置和大小。

  4. 处理子视图的添加和移除:根据需要重写 addView() removeView() 方法来处理子视图的添加和移除操作,并在需要的时候更新布局。

  5. 处理触摸事件:根据需要重写 onTouchEvent() 方法来处理触摸事件,实现 ViewGroup 的交互逻辑。

  6. 添加自定义属性(可选):通过在 res/values/attrs.xml 文件中定义自定义属性,并在 ViewGroup 构造方法中获取和处理这些属性,可以增加自定义 ViewGroup 的灵活性。 

  7. 重写onDeaw()方法(可选):如果需要在 ViewGroup 上绘制自定义的图形或效果,可以重写 onDraw() 方法并使用 Canvas 绘制相关内容。

b.注意事项:
  1. 正确测量和布局:确保在 onMeasure() onLayout() 方法中正确计算和设置子视图的尺寸和位置,以避免布局错误。

  2. 避免过度嵌套:尽量避免过度嵌套子视图,以提高性能和布局效率。

  3. 处理不同屏幕尺寸:考虑不同屏幕尺寸和密度下的适配,确保自定义 ViewGroup 能正确适配各种设备。

  4. 优化绘制操作:使用硬件加速、缓存绘制结果等方式来优化绘制效率。

  5. 测试和调试:在开发过程中进行充分的测试和调试,确保自定义 ViewGroup 的布局行为符合预期。

  6. 文档和注释:为自定义 ViewGroup 添加清晰的文档和注释,方便他人理解和维护代码。

        自定义 ViewGroup 允许开发者创建具有特定布局规则和交互方式的容器,可以用于实现复杂的界面布局、列表视图、网格视图等。

c.简单示例  
          1.创建 CustomViewGroup.java 文件

        在 Android 应用开发中,通常会将自定义 View 类的代码放在一个 Java 文件中,该文件的路径可以根据项目结构进行灵活设置。一般来说,你可以在 src 目录下的相应包名路径中创建 CustomViewgroup.java 文件,其中包含自定义 View 类的代码。

        例如,小编的包名是 com.example.example, app/src/main/java/com.example.example目录下创建 CustomViewGroup.java 文件,并将上面提供的 CustomViewGroup 类代码放入其中。

package com.example.example;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class CustomViewGroup extends ViewGroup {

    public CustomViewGroup(Context context) {
        super(context);
        init();
    }

    public CustomViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        // 初始化操作,例如设置背景色、添加子视图等
        setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int maxWidth = 0;
        int totalHeight = 0;

        // 测量子视图的大小并设置布局规则
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
            totalHeight += child.getMeasuredHeight();
        }

        // 设置自身的宽度和高度
        setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(totalHeight, heightMeasureSpec));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        // 布局子视图的位置和大小的逻辑
        // 布局子视图的位置和大小的逻辑
        int childCount = getChildCount();
        int parentLeft = getPaddingLeft();
        int parentTop = getPaddingTop();

        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);

            // 计算子视图的位置和大小
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            // 设置子视图的位置
            int childLeft = parentLeft;
            int childTop = parentTop;

            // 布局子视图
            child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);

            // 更新父布局的top位置
            parentTop += childHeight;
        }
    }
}
        2.在布局文件(如 activity_main.xml)中添加 CustomViewGroup
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal">

    <!-- <com.yourpackage.CustomViewGroup  -->
    <com.example.example.CustomViewGroup
        android:id="@+id/CustomViewGroup"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!-- 这里可以添加子视图 -->
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/button"
            style="@style/style1"
            android:text="@string/login" />
        <!-- <com.yourpackage.CustomView  刚刚自定义的View -->
        <com.example.example.CustomView
            android:id="@+id/custom_view"
            android:layout_width="match_parent"
            android:layout_height="200dp" />

    </com.example.example.CustomViewGroup>
        3.在 Activity (如MainActivity)中找到 CustomViewGroup 并进行操作
package com.example.example;

import android.os.Bundle; 
import android.view.View; 
import android.widget.TextView; 
import androidx.appcompat.app.AppCompatActivity; 

public class MainActivity extends AppCompatActivity { 
    private CustomView customView;
    private CustomViewGroup  CustomViewGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 调用 CustomViewGroup
        CustomViewGroup = findViewById(R.id.CustomViewGroup);
        // 可以通过代码动态添加子视图
        TextView textView = new TextView(this);
        textView.setText("添加文字..");
        CustomViewGroup.addView(textView);  
        // 调用CustomView
        customView = findViewById(R.id.custom_view);
//         可以根据需要对 CustomView 进行操作,例如设置监听器
        customView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { }
        });

    } 
}
          4.运行应用查看效果

在以上示例代码中,通过继承 View 或 ViewGroup 类,重写了关键的方法,以实现自定义的视图或容器。通过在 onMeasure() 方法中测量视图大小、设置布局规则,在 onLayout() 方法中布局子视图的位置和大小,以及在 onDraw() 方法中绘制自定义内容,可以实现各种自定义效果和交互行为。
需要注意的是,这些示例代码仅为了说明概念,并不包含完整的实现细节。实际开发中,我们还需要根据具体需求进行进一步的代码编写和调试,确保自定义 View 或 ViewGroup 能够正确地呈现预期的效果。 

三、总结: 

自定义 View 和自定义 ViewGroup 是 Android 开发中常用的技术手段,用于实现各种独特的界面效果和交互行为。通过继承现有的 View ViewGroup 类,重写相关方法,并根据实际需求定制绘制逻辑、布局规则和用户交互处理,可以创建出完全符合自己需求的自定义视图和容器。在实现自定义 View 和自定义 ViewGroup 的过程中,需要注意测量、布局和绘制的流程和方法,以及合理处理子视图的添加和移除。这样可以最大程度地发挥 Android 平台的灵活性和定制性,为用户提供更好的应用体验。 

下期了解认识LinearLayout(线性布局)

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值