Android View使用、自定义和性能优化

简介: View的继承关系创建View对象使用XML布局定义View,再用代码控制View举例1.创建activity_view.xml文件2.加载布局文件、关联控件3.在获得XML布局文件中的视图对象时需要注意下面几点:4.用代码控制视图使用代码的方式来创建View对象实例1.获得当前的容器视图对象2.获得或创建待添加的视图对象3.将相应的视图对象添加到容器视图中总结自定义View为什么要自定义View自定义View的基本方法需要用到的两个对象自绘控件View实例1、直接继承View类2、在布局 XML 文件中使用自定义View性能优化

View的继承关系


       在Android系统中,「任何可视化控件」都需要从android.view.View类继承。而任何从android.view.View继承的类都可以称为视图(View)。Android的绝大部分UI组件都放在android.widget包及其子包,下图就是android.widget包中所有View及其 子类 的继承关系:


image.png


       从上图看,有很多布局类等为什么没有在上图看到,在这里要说明一下这里仅是android.widget包的,还有其他视图的虽然也继承View但是他们不属于android.widget包例如下面两个组件:


「RecyclerView」继承ViewGroup,但是属于androidx.recyclerview.widget包的。


「ConstraintLayout」继承ViewGroup,但是属于androidx.constraintlayout.widget包的;


其他还有很多其他包、或自定义控件,这里就不做过多描述了。


       Android中的视图类可分为3种:「布局(Layout)类」、「视图容器(View Container)类」和「视图类(例TextView)」,这3种类都是android.view.View的子类。ViewGroup是一个容器类,该类也是View的重要子类,所有的布局类和视图容器类都是ViewGroup的子类,而视图类直接继承自View类。 下图描述了View、ViewGroup、视图容器类及视图类的继承关系。


image.png


从上图所示的继承关系可以看出:


  • Button、TextView、EditText都是「视图类」,TextView是Button和EditText的父类,TextView直接继承自View类。


  • GridView和ListView是ViewGroup的子类,但并不是直接子类,GridView、ListView继承自AbsListView继承自AdapterView继承自ViewGroup,从而形成了「视图容器类」的层次结构。


  • 布局视图虽然也属于容器视图,但由于布局视图具有排版功能,所以将这类视图置为「布局类」


       对于一个Android应用的图形用户界面来说,ViewGroup作为容器来装其他组件,而ViewGroup里除了可以包含普通View组件之外,还可以再次包含ViewGroup组件。


image.png


创建View对象


使用XML布局定义View,再用代码控制View


       XML布局文件是Android系统中定义视图的常用方法,所有的XML布局文件必须保存在res/layout目录中。XML布局文件的命名及定义需要注意如下几点:


  • XML布局文件的扩展名必须是xml。


  • 由于aapt会根据每一个XML布局文件名在R类的内嵌类中生成一个int类型的变量,这个变量名就是XML布局文件名,因此,XML布局文件名(不包含扩展名)必须符合Java变量名的命名规则,例如,XML布局文件名不能以数字开头。


  • 每一个XML布局文件的根节点可以是任意的视图标签,如< LinearLayout >,< TextView >。


  • XML布局文件的根节点必须包含android命名空间,而且命名空间的值必须是xmlns:android=http://schemas.android.com/apk/res/android。


  • 为XML布局文件中的标签指定ID时需要使用这样的格式:@+id/tv_xml,其实@+id就是在R.java文件里新增一个id名称,在同一个xml文件中确保ID唯一。


  • 由于每一个视图ID都会在R.id类中生成与之相对应的变量,因此,视图ID的值也要符合Java变量的命名规则,这一点与XML布局文件名的命名规则相同。


举例


1.创建activity_view.xml文件


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/color_666666"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tv_xml"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="@dimen/dimen_20"
        android:background="@color/color_188FFF"
        android:padding="@dimen/dimen_10"
        android:text="XML设置TextView"
        android:textColor="@color/white"
        android:textSize="@dimen/text_size_18" />
    <Button
        android:id="@+id/btn_xml"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="@dimen/dimen_20"
        android:background="@color/color_188FFF"
        android:padding="@dimen/dimen_10"
        android:text="按钮"
        android:textColor="@color/white"
        android:textSize="@dimen/text_size_18" />
</LinearLayout>


2.加载布局文件、关联控件


       如果要使用上面的XML布局文件(activity_view.xml),通常需要在onCreate方法中使用setContentView方法指定XML布局文件的资源lD,并获取在activity_view.xml文件中定义的某个View,代码如下:


public class ViewActivity extends AppCompatActivity{
    private Button btnXml;
    private TextView tvXml;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //加载布局文件
        setContentView(R.layout.activity_view);
        //如果想获得在activity_view.xml文件中定义的某个View
        //关联控件:R.id.tv_xml是tvXml的ID,确保这个ID在R.layout.activity_view中
        tvXml = findViewById(R.id.tv_xml);
        //关联控件:R.id.btn_xml是btnXml的ID,确保这个ID在R.layout.activity_view中
        btnXml = findViewById(R.id.btn_xml);
    }
}


3.在获得XML布局文件中的视图对象时需要注意下面几点:


  • 先使用setContentView方法装载XML布局文件,再使用findViewByld方法,否则findViewByld方法会由于未找到控件而产生空指针异常,导致应用崩溃。


  • 虽然所有的XML布局文件中的视图ID都在R.id类中生成了相应的变量,但使用findViewByld方法只能获得已经装载的XML布局文件中的视图对象。
  • 例,activity_view.xml中TextView的对应R.id.tv_xml;


  • 其他XML文件中有TextView的R.id.tv_shuaiciid,tv_shuaici不在activity_view.xml中如果使用 tvXml = findViewById(R.id.tv_shuaici);


  • 结果应用崩溃。原因:在activity_view.xml中找不到ID为tv_shuaici的视图对象。


4.用代码控制视图


       虽然使用XML布局文件可以非常方便地对控件进行布局,但若想控制这些控件的行为,仍然需要编写Java代码。在上面介绍了使用findViewByld方法获得指定的视图对象,当获得视图对象后,就可以使用代码来控制这些视图对象了。例如,下面的代码获得了一个TextView对象,并修改了TextView的文本。


TextView tvXml = findViewById(R.id.tv_xml);
//直接使用字符串来修改TextView的文本
tvXml.setText("帅次");
//使用字符串资源(res/values/strings.xml)
//其中R.string.str_tv_shuaici是字符串资源ID,系统会使用这个ID对应的字符串设置TextView的文本。
tvXml.setText(R.string.str_tv_shuaici);

「选择其中一样即可」,如果同时设置,最后一次设置为最终结果。


使用代码的方式来创建View对象


       在更高级的Android应用中,往往需要动态添加视图。要实现这个功能,最重要的是获得当前的视图容器对象,这个容器对象所对应的类需要继承ViewGroup类。 将其他的视图添加到当前的容器视图中需要如下几步:


  • 第1步,获得当前的容器视图对象;


  • 第2步,获得或创建待添加的视图对象;


  • 第3步,将相应的视图对象添加到容器视图中。


实例


1.获得当前的容器视图对象

//1、获取activity_view.xml中LinearLayout对象
 //2、也可以给LinearLayout添加@+id/,然后通过findViewById关联控件也能获取LinearLayout对象
LinearLayout linearLayout =
        (LinearLayout)getLayoutInflater().inflate(R.layout.activity_view,null);
//加载布局文件
setContentView(linearLayout);

2.获得或创建待添加的视图对象

EditText editText = new EditText(this);
editText.setHint("请输入内容");

3.将相应的视图对象添加到容器视图中

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //1、获取activity_view.xml中LinearLayout对象
        //2、也可以给LinearLayout添加@+id/,然后通过findViewById关联控件也能获取LinearLayout对象
        LinearLayout linearLayout =
                (LinearLayout)getLayoutInflater().inflate(R.layout.activity_view,null);
        //加载布局文件
        setContentView(linearLayout);
        EditText editText = new EditText(this);
        editText.setHint("请输入内容");
        linearLayout.addView(editText);
    }

   

 效果图如下:


image.png




总结

  • 实际上不管使用那种方式,他们创建Android用户界面行为的本质是完全一样的。大部分时候,设置UI组件的XML属性还有对应的方法。


  • 对于View类而言,它是所有UI组件的基类,因此它包含的XML属性和方法是所有组件都可以使用的。


自定义View


为什么要自定义View


       Android系统提供了一系列的原生控件,但这些原生控件并不能够满足我们的需求时,我们就需要自定义View了。


自定义View的基本方法


       自定义View的最基本的三个方法分别是: onMeasure()、onLayout()、onDraw(); View在Activity中显示出来,要经历测量、布局和绘制三个步骤,分别对应三个动作:measure、layout和draw。


  • 测量:onMeasure()决定View的大小;


  • 布局:onLayout()决定View在ViewGroup中的位置;


  • 绘制:onDraw()决定绘制这个View。

image.png



需要用到的两个对象

  • Canvas(画布),可在画布上面绘制东西,绘制的内容取决于所调用的方法。如drawCircle方法,用来绘制圆形,需要我们传入圆心的x和y坐标,以及圆的半径。


  • Paint(画笔),用来告诉画布,如何绘制那些要被绘制的对象。


这两个方法暂时了解就行,如果拓展开,这不够写,后面可能会针对这两个对象单独拉一个章节出来。


自绘控件View实例


1、直接继承View类


       自绘View控件时,最主要工作就是绘制出丰富的内容,这一过程是在重写的onDraw方法中实现的。由于是View,它没有子控件了,所以重写onLayout没有意义。onMeasure的方法可以根据自己的需要来决定是否需要重写,很多情况下,不重写该方法并不影响正常的绘制。


/**
 * 创建人:scc
 * 功能描述:自定义View
 */
public class CustomView extends View {
    private Paint paint;
    //从代码创建视图时使用的简单构造函数。
    public CustomView(Context context) {
        super(context);
    }
    //从XML使用视图时调用的构造函数。
    public CustomView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    //View的绘制工作
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //实例化画笔对象
        paint = new Paint();
        //给画笔设置颜色
        paint.setColor(Color.RED);
        //设置画笔属性
        //paint.setStyle(Paint.Style.FILL);//画笔属性是实心圆
        paint.setStyle(Paint.Style.STROKE);//画笔属性是空心圆
        paint.setStrokeWidth(10);//设置画笔粗细
        //cx:圆心的x坐标;cy:圆心的y坐标;参数三:圆的半径;参数四:定义好的画笔
        canvas.drawCircle(getWidth() / 4, getHeight() / 4, 150, paint);
    }
}


2、在布局 XML 文件中使用自定义View


<com.scc.demo.view.CustomView
        android:id="@+id/view_circle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

3、实现效果:


image.png


性能优化


在自定义View时需要注意,避免犯以下的性能错误


  • 在非必要时,对View进行重绘。


  • 绘制一些不被用户所看到的的像素,也就是过度绘制。(被覆盖的地方)


  • 在绘制期间做了一些非必要的操作,导致内存资源的消耗。


可进一步了解和优化

  • View.invalite()是最最广泛的使用操作,因为在任何时候都是刷新和更新视图最快的方式。

在自定义View时要小心避免调用非必要的方法,因为这样会导致重复强行绘制整个视图层级,消耗宝贵的帧绘制周期。检查清楚View.invalite()和View.requestLayout()方法调用时间位置,因为这会影响整个UI,导致GPU和它的帧速率变慢。


  • 避免过渡重绘。为了避免过渡重绘,我们可以利用Canvas方法,只绘制控件中所需要的部分。整个一般在重叠部分或控件时特别有用。相应的方法是Canvas.clipRect()(指定要被绘制的区域);


  • 在实现View.onDraw()方法中,不应该在方法内及调用的方法中进行任何的对象分配。在该方法中进行对象分配,对象会被创建和初始化。而当View.onDraw()方法执行完毕时。垃圾回收器会释放内存。如果View带动画,那么View在一秒内会被重绘60次。所以要避免在View.onDraw()方法中分配内存。


永远不要在View.onDraw()方法中及调用的方法中进行内存分配,避免带来负担。垃圾回收器多次释放内存,会导致卡顿。最好的方式就是在View被首次创建出来时,实例化这些对象。


       到这里View基本差不多了,还有其他属性、方法、事件等,在后面的TexView、Button、Layout等中慢慢了解,最后附上超级大图。


微信图片_20220519161509.jpg

相关文章
|
24天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
94 4
|
27天前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
23 1
|
2月前
|
算法 数据处理 Android开发
掌握安卓性能优化的秘诀:电池寿命与运行效率的提升
【10月更文挑战第6天】 本文深入探讨了安卓应用开发中的性能优化技巧,重点分析了影响电池寿命和运行效率的关键因素,并提供了针对性的优化策略。通过代码优化、资源管理、后台任务处理等方法,开发者可以显著提升应用的续航能力和流畅度。同时,结合具体案例,展示了如何在实际开发中应用这些技巧,确保应用在各种场景下都能保持高效运行。本文旨在为安卓开发者提供实用的性能优化指导,助力其打造更优质的应用体验。
65 2
|
2月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
94 0
|
16天前
|
网络协议 Linux Android开发
深入探索Android系统架构与性能优化
本文旨在为读者提供一个全面的视角,以理解Android系统的架构及其关键组件。我们将探讨Android的发展历程、核心特性以及如何通过有效的策略来提升应用的性能和用户体验。本文不包含常规的技术细节,而是聚焦于系统架构层面的深入分析,以及针对开发者的实际优化建议。
29 1
|
27天前
|
XML 前端开发 Android开发
Android:UI:Drawable:View/ImageView与Drawable
通过本文的介绍,我们详细探讨了Android中Drawable、View和ImageView的使用方法及其相互关系。Drawable作为图像和图形的抽象表示,提供了丰富的子类和自定义能力,使得开发者能够灵活地实现各种UI效果。View和ImageView则通过使用Drawable实现了各种图像和图形的显示需求。希望本文能为您在Android开发中使用Drawable提供有价值的参考和指导。
40 2
|
1月前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
1月前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
1月前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
37 5