Android自定义View绘图基础

简介: 转载请说明出处! 作者:kqw攻城狮 出处:个人站 | CSDNAndroid自定义View绘图基础Android自定义View绘图基础View的测量View的...

转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


Android自定义View绘图基础

View的测量

控件的测量可以说是固定写法,原生的View只支持EXACTLY的测量模式,我们自定义的控件可以重写onMeasure方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getMeasuredSize(widthMeasureSpec), getMeasuredSize(heightMeasureSpec));
}

onMeasure方法给我们返回的widthMeasureSpecheightMeasureSpec,我们并不能直接拿过来使用,需要使用MeasureSpec类进行解析,来获取测量后的具体值。
首先需要获取测量模式

MeasureSpec.getMode(measureSpec)

getMode方法返回是测量的模式,有以下3种类型:
- MeasureSpec.EXACTLY : 精确值模式(指定值/match_parent)
- MeasureSpec.AT_MOST : 最大值模式(wrap_content)
- MeasureSpec.UNSPECIFIED : 不指定大小的测量模式(一般用不上)

获取到了测量模式以后,获取测量后的大小

MeasureSpec.getSize(measureSpec)

根据上面的意思,可以封装我们的getMeasuredSize方法

// 默认大小
private static final int DEFAULT_SIZE = 200;

/**
 * 获取测量后的大小
 *
 * @param measureSpec measureSpec
 * @return measuredSize
 */
private int getMeasuredSize(int measureSpec) {
    switch (MeasureSpec.getMode(measureSpec)) {
        case MeasureSpec.EXACTLY: // 精确值模式(指定值/match_parent)
            Log.i(TAG, "getMeasuredSize: 精确值模式");
            return MeasureSpec.getSize(measureSpec);
        case MeasureSpec.AT_MOST: // 最大值模式(wrap_content)
            Log.i(TAG, "getMeasuredSize: 最大值模式");
            return Math.min(DEFAULT_SIZE, MeasureSpec.getSize(measureSpec));
        case MeasureSpec.UNSPECIFIED: // 不指定大小的测量模式
            return DEFAULT_SIZE;
        default:
            return DEFAULT_SIZE;
    }
}

现在我们自定义的View就支持自定义的大小了,包括match_parentwrap_content具体值

View的绘制

画笔属性

创建画笔

Paint paint = new Paint();
方法 描述 举例
public void setAntiAlias(boolean aa) 设置画笔锯齿效果 true 无锯齿效果
public void setColor(@ColorInt int color) 设置画笔颜色
public void setARGB(int a, int r, int g, int b) 设置画笔的A、R、G、B值
public void setAlpha(int a) 设置画笔的Alpha值
public void setTextSize(float textSize) 设置字体的尺寸
public void setStyle(Style style) 设置画笔的风格(空心或实心) paint.setStyle(Paint.Style.STROKE);// 空心 paint.setStyle(Paint.Style.FILL); // 实心
public void setStrokeWidth(float width) 设置空心边框的宽度

Shader

BitmapShader, ComposeShader, LinearGradient, RadialGradient, SweepGradient

/**
 * Helper for drawPoints() for drawing a single point.
 */
public void drawPoint(float x, float y, @NonNull Paint paint)
canvas.drawPoint(10, 10, paint);

直线

绘制一条直线

/**
 * Draw a line segment with the specified start and stop x,y coordinates,
 * using the specified paint.
 *
 * <p>Note that since a line is always "framed", the Style is ignored in the paint.</p>
 *
 * <p>Degenerate lines (length is 0) will not be drawn.</p>
 *
 * @param startX The x-coordinate of the start point of the line
 * @param startY The y-coordinate of the start point of the line
 * @param paint  The paint used to draw the line
 */
public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint)

绘制多条直线

public void drawLines(@Size(multiple=4) @NonNull float[] pts, @NonNull Paint paint)

矩形

/**
 * Draw the specified Rect using the specified paint. The rectangle will
 * be filled or framed based on the Style in the paint.
 *
 * @param left   The left side of the rectangle to be drawn
 * @param top    The top side of the rectangle to be drawn
 * @param right  The right side of the rectangle to be drawn
 * @param bottom The bottom side of the rectangle to be drawn
 * @param paint  The paint used to draw the rect
 */
public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)
canvas.drawRect(100, 100, 200, 200, paint);

这里写图片描述

圆角矩形

/**
 * Draw the specified round-rect using the specified paint. The roundrect
 * will be filled or framed based on the Style in the paint.
 *
 * @param rx    The x-radius of the oval used to round the corners
 * @param ry    The y-radius of the oval used to round the corners
 * @param paint The paint used to draw the roundRect
 */
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)
canvas.drawRoundRect(100, 100, 200, 200, 20, 20, paint);

这里写图片描述

/**
 * Draw the specified circle using the specified paint. If radius is <= 0,
 * then nothing will be drawn. The circle will be filled or framed based
 * on the Style in the paint.
 *
 * @param cx     The x-coordinate of the center of the cirle to be drawn
 * @param cy     The y-coordinate of the center of the cirle to be drawn
 * @param radius The radius of the cirle to be drawn
 * @param paint  The paint used to draw the circle
 */
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
// 画圆
canvas.drawCircle(200, 200, 100, paint);

这里写图片描述

扇形

/**
 * <p>Draw the specified arc, which will be scaled to fit inside the
 * specified oval.</p>
 *
 * <p>If the start angle is negative or >= 360, the start angle is treated
 * as start angle modulo 360.</p>
 *
 * <p>If the sweep angle is >= 360, then the oval is drawn
 * completely. Note that this differs slightly from SkPath::arcTo, which
 * treats the sweep angle modulo 360. If the sweep angle is negative,
 * the sweep angle is treated as sweep angle modulo 360</p>
 *
 * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
 * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
 *
 * @param startAngle Starting angle (in degrees) where the arc begins
 * @param sweepAngle Sweep angle (in degrees) measured clockwise
 * @param useCenter If true, include the center of the oval in the arc, and
                    close it if it is being stroked. This will draw a wedge
 * @param paint      The paint used to draw the arc
 */
public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)
// 扇形 起始角度0度 旋转角度120度
canvas.drawArc(100, 100, 200, 200, 0, 120, true, paint);

这里写图片描述

弧形

扇形通过调整属性,可以实现弧形的效果,首先画笔设置成空心

// 空心
paint.setStyle(Paint.Style.STROKE);

设置画扇形的useCenter参数为false

// 弧形 起始角度0度 旋转角度120度
canvas.drawArc(100, 100, 200, 200, 0, 120, false, paint);

这里写图片描述

椭圆

/**
 * Draw the specified oval using the specified paint. The oval will be
 * filled or framed based on the Style in the paint.
 */
public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)
// 椭圆
canvas.drawOval(100, 100, 500, 300, paint);

这里写图片描述

文字

/**
 * Draw the text, with origin at (x,y), using the specified paint. The
 * origin is interpreted based on the Align setting in the paint.
 *
 * @param text  The text to be drawn
 * @param x     The x-coordinate of the origin of the text being drawn
 * @param y     The y-coordinate of the baseline of the text being drawn
 * @param paint The paint used for the text (e.g. color, size, style)
 */
public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
// 文字
paint.setTextSize(30);
paint.setColor(Color.BLACK);
canvas.drawText("KongQingwei", 100, 100, paint);

这里写图片描述

在指定位置显示每个字符

/**
 * Draw the text in the array, with each character's origin specified by
 * the pos array.
 *
 * @param text  The text to be drawn
 * @param pos   Array of [x,y] positions, used to position each character
 * @param paint The paint used for the text (e.g. color, size, style)
 *
 * @deprecated This method does not support glyph composition and decomposition and
 * should therefore not be used to render complex scripts. It also doesn't
 * handle supplementary characters (eg emoji).
 */
@Deprecated
public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos, @NonNull Paint paint)
canvas.drawPosText("KongQingwei", new float[]{
        30,30,
        60,60,
        90,90,
        120,120,
        150,150,
        180,180,
        210,210,
        240,240,
        270,270,
        300,300,
        330,330
}, paint);

这里写图片描述

绘制路径

可以自定义画出想要的任意图形

五角星

/**
 * Draw the specified path using the specified paint. The path will be
 * filled or framed based on the Style in the paint.
 *
 * @param path  The path to be drawn
 * @param paint The paint used to draw the path
 */
public void drawPath(@NonNull Path path, @NonNull Paint paint)
Path path = new Path();
path.moveTo(0,100);
path.lineTo(250,300);
path.lineTo(150,0);
path.lineTo(50,300);
path.lineTo(300,100);
path.lineTo(0,100);
canvas.drawPath(path,paint);

这里写图片描述

空心

paint.setStyle(Paint.Style.STROKE);

这里写图片描述

图形裁剪

以上面的实心五角星为例,以五角星的中心为圆心,裁剪出一个半径为100的圆形

/**
    * Modify the current clip with the specified path.
 *
 * @param path The path to operate on the current clip
 * @param op   How the clip is modified
 * @return     true if the resulting is non-empty
 */
public boolean clipPath(@NonNull Path path, @NonNull Region.Op op)
// 裁剪一个圆形
Path path = new Path();
path.reset();
path.addCircle(150, 150, 100, Path.Direction.CCW);
canvas.clipPath(path, Region.Op.INTERSECT);
// canvas.save();
// 画五角星
path.reset();
path.moveTo(0,100);
path.lineTo(250,300);
path.lineTo(150,0);
path.lineTo(50,300);
path.lineTo(300,100);
path.lineTo(0,100);
canvas.drawPath(path,paint);

这里写图片描述

Region.Op 描述 样式
INTERSECT 裁剪内部交集 这里写图片描述
DIFFERENCE 外部 这里写图片描述
相关文章
|
2月前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
43 1
|
3月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
133 0
|
2月前
|
XML 前端开发 Android开发
Android:UI:Drawable:View/ImageView与Drawable
通过本文的介绍,我们详细探讨了Android中Drawable、View和ImageView的使用方法及其相互关系。Drawable作为图像和图形的抽象表示,提供了丰富的子类和自定义能力,使得开发者能够灵活地实现各种UI效果。View和ImageView则通过使用Drawable实现了各种图像和图形的显示需求。希望本文能为您在Android开发中使用Drawable提供有价值的参考和指导。
51 2
|
2月前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
2月前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
48 5
|
3月前
|
缓存 数据处理 Android开发
在 Android 中使用 RxJava 更新 View
【10月更文挑战第20天】使用 RxJava 来更新 View 可以提供更优雅、更高效的解决方案。通过合理地运用操作符和订阅机制,我们能够轻松地处理异步数据并在主线程中进行 View 的更新。在实际应用中,需要根据具体情况进行灵活运用,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在 Android 中使用 RxJava 更新 View 的技巧和方法,为开发高质量的 Android 应用提供有力支持。
|
3月前
|
缓存 调度 Android开发
Android 在子线程更新 View
【10月更文挑战第21天】在 Android 开发中,虽然不能直接在子线程更新 View,但通过使用 Handler、AsyncTask 或 RxJava 等方法,可以实现子线程操作并在主线程更新 View 的目的。在实际应用中,需要根据具体情况选择合适的方法,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在子线程更新 View 的技巧和方法,为开发高质量的 Android 应用提供支持。
58 2
|
3月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
3月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
32 2
|
3月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。

热门文章

最新文章