Android自定义View学习之旅(一)

说在前面

最近在学习自定义View的实现,发现自己对自定义View的Api非常陌生,而自定义View也属于Android中非常重要的组成部分,想着边学习边记个笔记吧。

大部分的学习内容都来自Hencoder,下面跟着凯哥一起动手学学自定义view。

自定义View的关键类是Canvas和Paint,Paint作为参数传入Canvas的相应绘制方法中。我理解的Paint和Canvas的关系就像Paint是绘制风格,Canvas控制绘制细节。

让我们开始

首先我们新建了一个自定义View继承View,我们把它叫做ClassOne,放在布局文件activity_main.xml中:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.abilix.learn.algorithms.MainActivity">
    <com.abilix.learn.algorithms.ClassOne
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>
然后我们重写ClassOne中的onDraw方法:

public class ClassOne extends View {
    //一些构造函数
    Paint paint = new Paint();
    @Override
    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
        canvas.drawCircle(100,100,100,paint);
    }
}
这样我们build一下就得到了下面这样的效果(请忽略项目的名称QAQ):

这里的
canvas.drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
cxcy分别表示在一个以画布 左上角为坐标轴原点, 以即将绘制的圆的圆心为零点 正右方向为x正半轴, 正下方向为y轴正半轴的偏移量, radious是圆的半径,paint这里我们默认传入了无参构造函数得到的paint。
canvas的绘制方法还有很多,除了这里的drawCircle之外,还有许多以draw开头的绘制方法,部分方法还有许多种重载(天啊这也太复杂了吧)比如:
drawBitmap
drawArc
drawColor
drawLines
drawPath
等等……
嗯,好像这些谷歌爸爸提供的官方文档里都写的很清楚了,但是作为在公司上网受限的我来说,还是只能一个一个百度一下他们到底是干啥用的(心塞塞的)。
drawBitMap
drawBitMap一共有五种重载方法:
drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint)
drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint)
drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint) 
drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint)
drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, @Nullable Paint paint)
drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, @Nullable Paint paint)
其中后两种方法已经被废弃了,我们来看看第一种:
drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint)
恩,乍一看应该和drawCircle很相似,也是偏移量,那么究竟如何还是要亲自码一码验证一下,我们使用Android自带的图片ic_launcher作为测试bitmap,并且传入(left,top)的值为(0,0),(30,30),(-30,-30)试试:

嘛,和我们想的一样,说明咱的想象力还是可以的嘛,(#^.^#)嘻嘻
然后我们看第二个重载函数:
drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint)
为了更好得展示效果,看来得换张图片了,就用这张R.drawable.pic1好了

猜想了一下如何让他实现和第一个重载一样的效果:
bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight());
然后我们进行:
canvas.drawBitmap(bitmap,rect1,rectF,paint);
得到的效果如图:

龟龟,好像我不太适合当程序员,改行当算命的吧……

然后我们改一下rect1:
bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);
rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight());
再看看效果:

看起来view的大小没变,但是里面这个bitmap被放大了,那么我就猜想一下第二个参数Rect是用于控制传入的bitmap上进行裁剪的区域的大小,而第三个参数RectF是控制绘画区域的大小(自动缩放)。

ok,验证一蛤:

(1) 只改变rectF

bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
rectF = new RectF(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);


(2)同时改变

bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);
rectF = new RectF(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);

效果:


恩,稳的不行。接下来再看看第三个重载函数吧:

drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint) 

诶,这两个都是Rect???而且和第二个重载的名字是一样的(src、dst),芽儿,有点猜不出了

不过初始的样子应该还是可以猜到的:

bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
rect2 = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());


然后我们通过改变第二,第三个参数形成三种情况:

(1)只改变第二个参数:

bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);
rect2 = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());


(2)只改变第三个参数:

bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
rect2 = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);


(3)同时改变第二个和第三个参数:
bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
rect1 = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);
rect2 = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);


喵喵喵喵喵?这不是一样吗???查看源码后发现:

      native_drawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
              dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
              bitmap.mDensity);
又去补充了一下Rect和RectF的区别,原来最大的区别是精度不同...

下面看看第四个重载:

drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint)
矩阵,恩,八成应该是进行几何变换的了,我们来试试常用的矩阵:

 bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.pic1);
 matrix = new Matrix();
 matrix.postRotate(45f,bitmap.getWidth()/2,bitmap.getHeight()/2);

效果:


美滋滋,正好下班,溜了溜了。周六继续分享下一期Android自定义View学习之旅(二)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值