自定义View时,用到Paint Canvas的一些温故,讲讲平时一些效果是怎么画的(基础篇 一)

转载请注明出处王亟亟的大牛之路

之前也有一个类似于画板的操作,但是不够详细,这边先补上链接,有兴趣的小伙伴可以看看http://blog.csdn.net/ddwhan0123/article/details/48804761

还是老规矩,将内容之前说下我们的一些知识点,今天的第一个知识点有点高DA上的名词“硬件加速”。

硬件加速:

问题1:这玩意有什么用?
在绘制View的时候支持硬件加速,充分利用GPU的特性,使得绘制更加平滑。

问题2:怎么用?
在AndroidManifest的Application 或者Activity节点<application android:hardwareAccelerated="true/false">就可以进行开关。或者用Java代码:getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
如果这些你都不喜欢,你只要那个类当中的某个View是对这部分功能有需求的,那么这样:view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 但是要记住Window只能打开,View只能关闭所以还是在Activity和Application层面操作吧。

问题3:非用不可吗?
如果你的View的绘制内容比较复杂,比较对多,还是建议开着,诸如画密度很细的那种虚线或者颜色区域超级复杂的一些试图的画还是开着吧,不然说不定你再挂个什么网络的操作万一客户机烂一点一个未响应提示就来了。

Paint:

这部分的内容就不提了,网上多如牛毛,贴一个写的比较简单易通的http://www.cnblogs.com/tianzhijiexian/p/4297170.html?utm_source=tuicool&utm_medium=referral
http://www.kancloud.cn/kancloud/android-tutorial/87246

Canvas:

如上,还是附上可参考的链接:http://blog.sina.com.cn/s/blog_61ef49250100qw9x.html
http://www.kancloud.cn/kancloud/android-tutorial/87261

性能优化(跟自定义绘图相关的):

1.设置缓存:View 中设置缓存属性.setDrawingCache为true
2.优化布局:tools目录下的layoutopt 命令
3.将Acitivity 中的Window 的背景图设置为空(默认不为空)。getWindow().setBackgroundDrawable(null);
4.采用SurfaceView在子线程刷新UI,:避免手势的处理和绘制在同一UI线程(普通View都这样做)。
5:采用JNI:将耗时间的处理放到c/c++层来处理。


主要来说下自定义控件重要的三个方法“onMeasure()”,“onDraw()”,“onLayout()”:

1.onMeasure()方法就是用于测量视图的大小的,不然你的空间永远都只是白屏,不是没画上去,而是没有尺寸。

measure()方法接收两个参数,widthMeasureSpec和heightMeasureSpec也就是宽度和长度。

MeasureSpec的值由specSize和specMode共同组成的,specSize是大小,specMode是规格。

有三种规格:1. EXACTLY,AT_MOST,UNSPECIFIED。这三种规格细说太复杂了,我整合给大家听下

(1):子视图的大小应该是由specSize的值来决定,用户也可自行定义

(2):子视图最多只能是specSize中指定的大小,只能更小不能更大了

(3):可以将视图按照自己的意愿设置成任意的大小,没有任何限制

当rootDimension参数等于MATCH_PARENT的时候,MeasureSpec的specMode就等于EXACTLY,当rootDimension等于WRAP_CONTENT的时候,MeasureSpec的specMode就等于AT_MOST。并且MATCH_PARENT和WRAP_CONTENT时的specSize都是等于windowSize的,也就意味着根视图总是会充满全屏的。
这里的rootDimension是根布局的尺寸

总结:视图大小的控制是由父视图、布局文件、以及视图本身共同完成的,父视图会提供给子视图参考的大小,而开发人员可以在XML文件中指定视图的大小,然后视图本身会对最终的大小进行拍板。
不然就会出现onCreate时发现控件宽高都是0,之前有提到,看这里http://blog.csdn.net/ddwhan0123/article/details/50386685

2.onLayout()用于给视图进行布局的,也就是确定视图的位置,会在onMeasure方法之后执行。

layout()方法接收四个参数,分别代表着左、上、右、下的坐标,当然这个坐标是相对于当前视图的父视图而言的。

像这样layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
但是绘图的位置操作我们可以在onDraw里执行,所以如果你不想了解这部分,这方法你不調用都行,但是要记得在画的时候重现位置特性,不然就是“一坨屎在一起了”

3.onDraw(),measure和layout的过程都结束后,接下来就进入到这个方法了。我们所有的作画的事,都在这干!

ViewRoot中的代码会继续执行并创建出一个Canvas对象,然后调用View的draw()方法来执行具体的绘制工作

我们的绘画都是在这个Canvas对象的支持下实现的,简单写个例子。

public class TestView extends View {
    Paint paint;
    Context context;

    public TestView(Context context) {
        super(context);
        this.context = context;
    }

    public TestView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        paint = new Paint();
//        paint.setColor(getResources().getColor(R.color.SlateBlue));
        paint.setColor(getResources().getColor(R.color.Gold));
        paint.setStrokeWidth(3);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("--->onDraw", "onDraw()");
//        canvas.drawCircle(0, 0, 90, paint);
        canvas.drawCircle(100, 100, 90, paint);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        Log.d("--->onLayout", "changed = " + changed + " left = " + left + " top = " + top + " right = " + right + " bottom " + bottom);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.d("--->onMeasure", "  widthMeasureSpec =" + widthMeasureSpec + "  heightMeasureSpec = " + heightMeasureSpec);
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }
}

注释部分运行效果:
这里写图片描述

现有代码效果:
这里写图片描述

打印的顺序
这里写图片描述

请仔细看onLayout()的那些坐标,他任然保持着父布局的一系列属性参数:

  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"

相关资源收集:http://blog.csdn.net/michaelcao1980/article/details/43233909

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android自定义View中的Canvas是一个绘图容器,可以在其上进行2D绘图操作。通过Canvas,我们可以绘制图形、文字、位图等。 要在自定义View中使用Canvas,需要重写View的onDraw()方法,并在该方法中获取Canvas实例,然后进行绘制操作。 下面是一个简单的示例代码,展示如何在自定义View中使用Canvas绘制一个矩形: ```java public class MyCustomView extends View { public MyCustomView(Context context) { super(context); } public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawRect(100, 100, 300, 300, paint); } } ``` 在这个示例中,我们创建了一个名为MyCustomView自定义View,并重写了它的onDraw()方法。在该方法中,我们首先创建了一个Paint对象,设置了笔的颜色为红色,并指定绘制的样式为填充。然后,使用Canvas的drawRect()方法绘制一个矩形,坐标为(100, 100)到(300, 300)。 当我们在布局文件中使用这个自定义View,它会自动调用onDraw()方法进行绘制,从而在屏幕上显示出红色矩形。 需要注意的是,Canvas提供了许多其他绘制方法,如drawCircle()、drawText()等,可以根据需求选择合适的方法进行绘制操作。此外,还可以通过设置Paint对象的属性来实现不同的绘制效果,如线条宽度、字体大小等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值