Android Studio App自定义控件中自定义视图的绘制讲解及实战(附源码 包括自定义绘制各种图形)

简介: Android Studio App自定义控件中自定义视图的绘制讲解及实战(附源码 包括自定义绘制各种图形)

需要代码和图片集或者运行有问题请点赞关注收藏后评论区留言~~~

一、视图的绘制方法

测量完控件的宽高,接下来就要 绘制控件图案了,此时可以重写两个视图绘制方法,分别是onDraw和dispatchDraw,它们的区别主要有以下两点

1:onDraw既可用于普通控件,也可用于布局类视图,而dispatchDraw专门用于布局类视图,像线性布局LinearLayout,相对布局RelativeLayout都属于布局类视图

2:onDraw方法先执行,dispatchDraw方法后执行,这两个方法中间再执行下级视图的绘制方法

 

它们绘制方法的执行顺序如下图

不管是onDraw方法还是dispatchDraw方法,它们的入参都是Canvas画布对象,在画布上绘图相当于在屏幕上绘图,绘图本身是个很大的课题,画布的用法也多种多样,Canvas提供了下列三种方法

1:划定可绘制的区域

2:在区域内部绘制图形

3:画布的控制操作

接下来演示如何通过画布和画笔描绘不同的几何图形,以绘制圆角矩形与其他图形为例

初始化为不画图 但是点击下拉框可以选择图形

选择矩形如下

选择圆形如下

选择画叉叉如下

代码如下

Java类

package com.example.chapter10;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import androidx.appcompat.app.AppCompatActivity;
import com.example.chapter10.widget.DrawRelativeLayout;
public class ShowDrawActivity extends AppCompatActivity {
    private DrawRelativeLayout drl_content; // 声明一个绘画布局对象
    private Button btn_center;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_show_draw);
        // 从布局文件中获取名叫drl_content的绘画布局
        drl_content = findViewById(R.id.drl_content);
        btn_center = findViewById(R.id.btn_center);
        initTypeSpinner(); // 初始化绘图方式的下拉框
    }
    // 初始化绘图方式的下拉框
    private void initTypeSpinner() {
        ArrayAdapter<String> drawAdapter = new ArrayAdapter<String>(this,
                R.layout.item_select, descArray);
        Spinner sp_draw = findViewById(R.id.sp_draw);
        sp_draw.setPrompt("请选择绘图方式");
        sp_draw.setAdapter(drawAdapter);
        sp_draw.setOnItemSelectedListener(new DrawSelectedListener());
        sp_draw.setSelection(0);
    }
    private String[] descArray = {"不画图", "画矩形", "画圆角矩形", "画圆圈", "画椭圆",
            "onDraw画叉叉", "dispatchDraw画叉叉"};
    private int[] typeArray = {0, 1, 2, 3, 4, 5, 6};
    class DrawSelectedListener implements OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            int type = typeArray[arg2];
            if (type == 5 || type == 6) {
                btn_center.setVisibility(View.VISIBLE);
            } else {
                btn_center.setVisibility(View.GONE);
            }
            drl_content.setDrawType(type); // 设置绘图布局的绘制类型
        }
        public void onNothingSelected(AdapterView<?> arg0) {}
    }
}

按钮类如下

package com.example.chapter10.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;
import com.example.chapter10.R;
@SuppressLint("AppCompatCustomView")
public class CustomButton extends Button {
    private final static String TAG = "CustomButton";
    public CustomButton(Context context) {
        super(context);
        Log.d(TAG, "只有一个输入参数");
    }
    public CustomButton(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.customButtonStyle);
        Log.d(TAG, "有两个输入参数");
    }
    public CustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
        // 使defStyleAttr奏效的三个条件:
        // 1、attrs.xml增加定义风格属性(如customButtonStyle),且format值为reference
        // 2、styles.xml增加某种风格的样式定义(如CommonButton)
        // 3、AndroidManifest.xml的application节点的android:theme指定了哪个主题(如AppTheme),就在该主题内部补充风格属性与样式的对应关系,如
        // <item name="customButtonStyle">@style/CommonButton</item>
        //super(context, attrs, defStyleAttr); // 设置默认的样式属性
        // 下面不使用defStyleAttr,直接使用R.style.CommonButton定义的样式
        this(context, attrs, 0, R.style.CommonButton);
        Log.d(TAG, "有三个输入参数");
    }
    @SuppressLint("NewApi")
    public CustomButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        Log.d(TAG, "有四个输入参数");
    }
}

下拉框如下

package com.example.chapter10.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import androidx.viewpager.widget.PagerTabStrip;
import com.example.chapter10.R;
import com.example.chapter10.util.Utils;
public class CustomPagerTab extends PagerTabStrip {
    private final static String TAG = "CustomPagerTab";
    private int textColor = Color.BLACK; // 文本颜色
    private int textSize = 15; // 文本大小
    public CustomPagerTab(Context context) {
        super(context);
    }
    public CustomPagerTab(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (attrs != null) {
            // 根据CustomPagerTab的属性定义,从XML文件中获取属性数组描述
            TypedArray attrArray = context.obtainStyledAttributes(attrs, R.styleable.CustomPagerTab);
            // 根据属性描述定义,获取XML文件中的文本颜色
            textColor = attrArray.getColor(R.styleable.CustomPagerTab_textColor, textColor);
            // 根据属性描述定义,获取XML文件中的文本大小
            // getDimension得到的是px值,需要转换为sp值
            textSize = Utils.px2sp(context, attrArray.getDimension(
                    R.styleable.CustomPagerTab_textSize, textSize));
            Log.d(TAG, "origin textSize="+attrArray.getDimension(
                    R.styleable.CustomPagerTab_textSize, textSize));
            Log.d(TAG, "textColor=" + textColor + ", textSize=" + textSize);
            attrArray.recycle(); // 回收属性数组描述
        }
    }
//    //PagerTabStrip没有三个参数的构造方法
//    public CustomPagerTab(Context context, AttributeSet attrs, int defStyleAttr) {
//    }
    @Override
    protected void onDraw(Canvas canvas) { // 绘制方法
        super.onDraw(canvas);
        setTextColor(textColor); // 设置标题文字的文本颜色
        setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize); // 设置标题文字的文本大小
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp" >
        <TextView
            android:id="@+id/tv_draw"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:gravity="center"
            android:text="绘图方式:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Spinner
            android:id="@+id/sp_draw"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/tv_draw"
            android:gravity="left|center"
            android:spinnerMode="dialog" />
    </RelativeLayout>
    <!-- 自定义的绘画视图,需要使用全路径 -->
    <com.example.chapter10.widget.DrawRelativeLayout
        android:id="@+id/drl_content"
        android:layout_width="match_parent"
        android:layout_height="150dp" >
        <Button
            android:id="@+id/btn_center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:layout_centerInParent="true"
            android:text="我在中间"
            android:textColor="@color/black"
            android:textSize="20sp"
            android:visibility="gone" />
    </com.example.chapter10.widget.DrawRelativeLayout>
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
4天前
|
测试技术 Android开发
Android App获取不到pkgInfo信息问题原因
Android App获取不到pkgInfo信息问题原因
14 0
|
28天前
|
Java Android开发
Android Studio的使用导入第三方Jar包
Android Studio的使用导入第三方Jar包
12 1
|
1月前
|
缓存 移动开发 Java
构建高效Android应用:内存优化实战指南
在移动开发领域,性能优化是提升用户体验的关键因素之一。特别是对于Android应用而言,由于设备和版本的多样性,内存管理成为开发者面临的一大挑战。本文将深入探讨Android内存优化的策略和技术,包括内存泄漏的诊断与解决、合理的数据结构选择、以及有效的资源释放机制。通过实际案例分析,我们旨在为开发者提供一套实用的内存优化工具和方法,以构建更加流畅和高效的Android应用。
|
1月前
|
开发框架 移动开发 JavaScript
SpringCloud微服务实战——搭建企业级开发框架(四十六):【移动开发】整合uni-app搭建移动端快速开发框架-环境搭建
正如优秀的软件设计一样,uni-app把一些移动端常用的功能做成了独立的服务或者插件,我们在使用的时候只需要选择使用即可。但是在使用这些服务或者插件时一定要区分其提供的各种服务和插件的使用场景,例如其提供的【uni-starter快速开发项目模版】几乎集成了移动端所需的所有基础功能,使用非常方便,但是其许可协议只允许对接其uniCloud的JS开发服务端,不允许对接自己的php、java等其他后台系统。
145 2
|
1月前
|
设计模式 测试技术 数据库
基于Android的食堂点餐APP的设计与实现(论文+源码)_kaic
基于Android的食堂点餐APP的设计与实现(论文+源码)_kaic
|
2月前
|
数据库 Android开发 数据库管理
【Android】使用android studio查看内置数据库信息
【Android】使用android studio查看内置数据库信息
76 0
|
2月前
|
算法 Java Android开发
安卓逆向 -- 实战某峰窝APP(静态分析)
安卓逆向 -- 实战某峰窝APP(静态分析)
26 0
|
2月前
|
网络协议 算法 Android开发
安卓逆向 -- 实战某峰窝APP(动态分析)
安卓逆向 -- 实战某峰窝APP(动态分析)
32 4
|
1月前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
88 3