android 自定义绘制,自定义绘制  |  Android 开发者  |  Android Developers

自定义视图最重要的部分是外观。绘制自定义视图可能很简单,也可能很复杂,具体取决于应用的需求。这节课将介绍一些最常见的操作。

除了本课程,您还可以在画布和可绘制对象中找到其他相关信息。

替换 onDraw()

绘制自定义视图最重要的一步是替换

但是,在调用任何绘制方法之前,必须先创建

创建绘制对象

需要绘制什么,由

如何绘制,由

例如,

因此,在绘制任何内容之前,您需要创建一个或多个PieChart 示例在名为 init 的方法中执行此操作,该方法是从 Java 的构造函数调用的,但我们可以在 Kotlin 中进行内联初始化:

Kotlin

private val textPaint = Paint(ANTI_ALIAS_FLAG).apply {

color = textColor

if (textHeight == 0f) {

textHeight = textSize

} else {

textSize = textHeight

}

}

private val piePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

style = Paint.Style.FILL

textSize = textHeight

}

private val shadowPaint = Paint(0).apply {

color = 0x101010

maskFilter = BlurMaskFilter(8f, BlurMaskFilter.Blur.NORMAL)

}Java

private void init() {

textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

textPaint.setColor(textColor);

if (textHeight == 0) {

textHeight = textPaint.getTextSize();

} else {

textPaint.setTextSize(textHeight);

}

piePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

piePaint.setStyle(Paint.Style.FILL);

piePaint.setTextSize(textHeight);

shadowPaint = new Paint(0);

shadowPaint.setColor(0xff101010);

shadowPaint.setMaskFilter(new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL));

...

提前创建对象是一项重要的优化措施。视图会非常频繁地重新绘制,并且许多绘制对象的初始化都需要占用很多资源。在

处理布局事件

为了正确绘制自定义视图,您需要知道它的大小。复杂的自定义视图通常需要根据其在屏幕上所占区域的大小和形状执行多次布局计算。不要妄自假设视图在屏幕上的大小。即使只有一个应用使用您的视图,该应用也需要处理纵向和横向模式下的不同屏幕尺寸、多种屏幕密度和各种宽高比。

尽管

系统会在首次为您的视图分配大小时调用 PieChart 示例中,PieChart 视图在

为视图指定大小时,布局管理器会假定其大小包含视图的所有内边距。您必须在计算视图大小时处理内边距值。以下是PieChart.onSizeChanged()的代码段,其中说明了如何执行此操作:

Kotlin

// Account for padding

var xpad = (paddingLeft + paddingRight).toFloat()

val ypad = (paddingTop + paddingBottom).toFloat()

// Account for the label

if (showText) xpad += textWidth

val ww = w.toFloat() - xpad

val hh = h.toFloat() - ypad

// Figure out how big we can make the pie.

val diameter = Math.min(ww, hh)Java

// Account for padding

float xpad = (float)(getPaddingLeft() + getPaddingRight());

float ypad = (float)(getPaddingTop() + getPaddingBottom());

// Account for the label

if (showText) xpad += textWidth;

float ww = (float)w - xpad;

float hh = (float)h - ypad;

// Figure out how big we can make the pie.

float diameter = Math.min(ww, hh);

如果您需要更精细地控制视图的布局参数,请实现

以下是 PieChart 尝试使其面积足够大,以使饼图大小与其标签一致:

Kotlin

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

// Try for a width based on our minimum

val minw: Int = paddingLeft + paddingRight + suggestedMinimumWidth

val w: Int = View.resolveSizeAndState(minw, widthMeasureSpec, 1)

// Whatever the width ends up being, ask for a height that would let the pie

// get as big as it can

val minh: Int = View.MeasureSpec.getSize(w) - textWidth.toInt() + paddingBottom + paddingTop

val h: Int = View.resolveSizeAndState(

View.MeasureSpec.getSize(w) - textWidth.toInt(),

heightMeasureSpec,

0

)

setMeasuredDimension(w, h)

}Java

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// Try for a width based on our minimum

int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();

int w = resolveSizeAndState(minw, widthMeasureSpec, 1);

// Whatever the width ends up being, ask for a height that would let the pie

// get as big as it can

int minh = MeasureSpec.getSize(w) - (int)mTextWidth + getPaddingBottom() + getPaddingTop();

int h = resolveSizeAndState(MeasureSpec.getSize(w) - (int)mTextWidth, heightMeasureSpec, 0);

setMeasuredDimension(w, h);

}

在此代码中,有三点需要注意:

计算时会考虑视图的内边距。如前文所述,这由视图负责计算。

辅助方法

绘制!

创建好对象并定义了测量代码后,您可以实现

使用

例如,以下代码绘制了 PieChart。它组合使用了文本、线条和形状。

Kotlin

override fun onDraw(canvas: Canvas) {

super.onDraw(canvas)

canvas.apply {

// Draw the shadow

drawOval(shadowBounds, shadowPaint)

// Draw the label text

drawText(data[mCurrentItem].mLabel, textX, textY, textPaint)

// Draw the pie slices

data.forEach {

piePaint.shader = it.mShader

drawArc(bounds,

360 - it.endAngle,

it.endAngle - it.startAngle,

true, piePaint)

}

// Draw the pointer

drawLine(textX, pointerY, pointerX, pointerY, textPaint)

drawCircle(pointerX, pointerY, pointerSize, mTextPaint)

}

}Java

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// Draw the shadow

canvas.drawOval(

shadowBounds,

shadowPaint

);

// Draw the label text

canvas.drawText(data.get(currentItem).mLabel, textX, textY, textPaint);

// Draw the pie slices

for (int i = 0; i < data.size(); ++i) {

Item it = data.get(i);

piePaint.setShader(it.shader);

canvas.drawArc(bounds,

360 - it.endAngle,

it.endAngle - it.startAngle,

true, piePaint);

}

// Draw the pointer

canvas.drawLine(textX, pointerY, pointerX, pointerY, textPaint);

canvas.drawCircle(pointerX, pointerY, pointerSize, mTextPaint);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值