android自定义View学习(二)----自定义绘图

自定义绘图

自定义视图中最重要的部分是它的外观。根据您的应用需求,自定义绘图可以很容易或复杂。本篇涵盖了一些最常见的操作

onDraw()

绘制自定义视图中最重要的步骤是重写该onDraw()方法。参数to onDraw()是Canvas视图可以用来绘制自己的对象。在Canvas 类定义绘制文字,线条,位图和许多其它图形图元的方法。您可以使用这些方法 onDraw()创建自定义用户界面(UI)。
但是,在您调用任何绘图方法之前,需要创建一个Paint 对象。下文将更详细地讨论。 (可以理解成绘制前需要一直笔,而这个笔就是Paint对象)

创建绘图对象

例如,Canvas提供了一种绘制线条的方法,同时 Paint提供了定义该线条颜色的方法。Canvas有一种方法来绘制一个矩形,同时Paint定义是用一种颜色填充该矩形还是将其留空。简单地说,Canvas定义可以在屏幕上绘制的形状,同时Paint定义绘制的每个形状的颜色,样式,字体等等。

所以,在绘制任何东西之前,您需要创建一个或多个Paint 对象。该PieChart示例在调用的方法中执行此操作init,该操作从构造函数中调用:

private void init() {
   mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
   mTextPaint.setColor(mTextColor);
   if (mTextHeight == 0) {
       mTextHeight = mTextPaint.getTextSize();
   } else {
       mTextPaint.setTextSize(mTextHeight);
   }

   mPiePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
   mPiePaint.setStyle(Paint.Style.FILL);
   mPiePaint.setTextSize(mTextHeight);

   mShadowPaint = new Paint(0);
   mShadowPaint.setColor(0xff101010);
   mShadowPaint.setMaskFilter(new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL));

   ...

提前创建对象是一项重要的优化。视图经常重绘,许多图形对象需要昂贵的初始化。在您的onDraw() 方法中创建绘图对象会显着降低性能,并可能导致UI显得呆滞。

处理布局事件

为了正确绘制自定义视图,您需要知道它的大小。复杂的自定义视图通常需要执行多个布局计算,具体取决于屏幕上区域的大小和形状。你绝对不应该对屏幕上的视图大小做出假设。即使只有一个应用使用您的视图,该应用也需要在纵向和横向模式下处理不同的屏幕尺寸,多种屏幕密度以及各种纵横比。

虽然View有许多处理度量的方法,但大多数方法不需要被覆盖。如果你的视图不需要特殊控制它的大小,你只需要重写一个方法:onSizeChanged()。

onSizeChanged()在您的视图首次分配大小时调用,并且如果视图的大小因任何原因而发生更改,则会再次调用该视图。计算与您的视图尺寸相关的位置,尺寸和任何其他值 onSizeChanged(),而不是每次绘制时重新计算它们。在该PieChart例子中,onSizeChanged()是在PieChart图计算饼图的外接矩形和文本标签和其他视觉元素的相对位置。

当您的视图分配了大小时,布局管理器会假定大小包含所有视图的填充。计算视图大小时,您必须处理填充值。这里有一个片段PieChart.onSizeChanged() 显示了如何做到这一点:

  // Account for padding
       float xpad = (float)(getPaddingLeft() + getPaddingRight());
       float ypad = (float)(getPaddingTop() + getPaddingBottom());

       // Account for the label
       if (mShowText) xpad += mTextWidth;

       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);

onMeasure()
如果您需要更好地控制视图的布局参数,请执行onMeasure()。此方法的参数是一些 View.MeasureSpec值,告诉您视图的父级希望您的视图有多大,以及该大小是一个硬性最大值还是仅仅是一个建议。作为优化,这些值被存储为打包整数,并使用静态方法 View.MeasureSpec来解压存储在每个整数中的信息。

这是一个示例实现onMeasure()。在这个实现中,PieChart 试图使它的面积足够大,以使饼与其标签一样大:

@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);
}

在这个代码中有三件重要的事情需要注意:

  • 计算考虑了视图的填充。如前所述,这是观点的责任。
  • 辅助方法resolveSizeAndState()用于创建最终的宽度和高度值。该帮助程序View.MeasureSpec通过将视图的所需大小与传入的规范进行比较来返回适当的 值 onMeasure()。
  • onMeasure()没有回报价值。相反,该方法通过调用来传递其结果setMeasuredDimension()。调用此方法是强制性的。如果您省略此调用,则View该类会引发运行时异常。

onDraw()

一旦你定义了对象创建和测量代码,你就可以实现onDraw()。每个视图的实现onDraw() 方式都不相同,但大多数视图共享一些常见操作:

  • 使用绘制文本drawText()。通过调用指定字体setTypeface(),并通过调用指定文字颜色setColor()。
  • 通过绘制基本形状drawRect(),drawOval()和drawArc()。通过调用来更改形状是否填充,勾勒或两者兼而有之setStyle()。
  • 使用Path该类绘制更复杂的形状。通过向Path对象添加直线和曲线来定义形状 ,然后使用绘制形状drawPath()。就像原始形状一样,根据路径可以勾勒出轮廓,填充或两者 setStyle()。
  • 通过创建LinearGradient对象来定义渐变填充。呼吁setShader()使用你 LinearGradient的填充形状。
  • 使用绘制位图drawBitmap()。
    例如,这里是绘制的代码PieChart。它使用文本,线条和形状的组合。
protected void onDraw(Canvas canvas) {
   super.onDraw(canvas);

   // Draw the shadow
   canvas.drawOval(
           mShadowBounds,
           mShadowPaint
   );

   // Draw the label text
   canvas.drawText(mData.get(mCurrentItem).mLabel, mTextX, mTextY, mTextPaint);

   // Draw the pie slices
   for (int i = 0; i < mData.size(); ++i) {
       Item it = mData.get(i);
       mPiePaint.setShader(it.mShader);
       canvas.drawArc(mBounds,
               360 - it.mEndAngle,
               it.mEndAngle - it.mStartAngle,
               true, mPiePaint);
   }

   // Draw the pointer
   canvas.drawLine(mTextX, mPointerY, mPointerX, mPointerY, mTextPaint);
   canvas.drawCircle(mPointerX, mPointerY, mPointerSize, mTextPaint);
}

Android自定义控件学习(三)----- 自定义视图组件
https://blog.csdn.net/qq_26296197/article/details/79775237

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值