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>

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

相关文章
|
18天前
|
监控 安全 开发者
山东布谷科技:关于直播源码|语音源码|一对一直播源码提交App Store的流程及重构经验
分享提交直播源码,一对一直播源码,语音源码到Appstore的重构经验!
|
20天前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码服务器环境配置及app功能
一对一直播源码阿里云服务器环境配置及要求
|
10天前
|
前端开发 Android开发 UED
安卓应用开发中的自定义控件实践
【10月更文挑战第35天】在移动应用开发中,自定义控件是提升用户体验、增强界面表现力的重要手段。本文将通过一个安卓自定义控件的创建过程,展示如何从零开始构建一个具有交互功能的自定义视图。我们将探索关键概念和步骤,包括继承View类、处理测量与布局、绘制以及事件处理。最终,我们将实现一个简单的圆形进度条,并分析其性能优化。
|
1月前
|
缓存 搜索推荐 Android开发
安卓开发中的自定义控件基础与进阶
【10月更文挑战第5天】在Android应用开发中,自定义控件是提升用户体验和界面个性化的重要手段。本文将通过浅显易懂的语言和实例,引导你了解自定义控件的基本概念、创建流程以及高级应用技巧,帮助你在开发过程中更好地掌握自定义控件的使用和优化。
40 10
|
16天前
|
机器人
布谷直播App系统源码开发之后台管理功能详解
直播系统开发搭建管理后台功能详解!
|
25天前
|
NoSQL PHP Redis
布谷语音app源码服务器环境配置及技术开发语言
布谷语音app源码服务器环境配置及技术语言研发。。
|
1月前
|
JavaScript 小程序 开发者
uni-app开发实战:利用Vue混入(mixin)实现微信小程序全局分享功能,一键发送给朋友、分享到朋友圈、复制链接
uni-app开发实战:利用Vue混入(mixin)实现微信小程序全局分享功能,一键发送给朋友、分享到朋友圈、复制链接
322 0
|
3月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
134 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
3月前
|
Dart 开发工具 Android开发
Android Studio导入Flutter项目提示Dart SDK is not configured
Android Studio导入Flutter项目提示Dart SDK is not configured
307 4
|
3月前
|
Java 开发工具 Android开发
Android Studio利用Build.gradle导入Git commit ID、Git Branch、User等版本信息
本文介绍了在Android Studio项目中通过修改`build.gradle`脚本来自动获取并添加Git的commit ID、branch名称和用户信息到BuildConfig类中,从而实现在编译时将这些版本信息加入到APK中的方法。
71 0

热门文章

最新文章