为什么要自定义View,是因为想要官方给的View达到我们自己的效果,同时减少嵌套,优化布局,就比如说本章涉及到的imagView,正常情况下我们只是显示图片本身,没办法定义其形状,但就是想要把它从正方形改成圆形,这就需要继承imageView,并重写onDraw方法即可
需要准备一张图片放在drawable中
涉及知识点:
Paint
画笔工具定义,可以选择颜色,风格等
Canvas
使用定义的画笔去绘制形状
BitmapShader图像着色器
BitmapShader图像着色器,可以理解为图像本身就是着色的效果,也就是你画出来的内容(填充)
矩阵matrix:这里用作按照比例缩小图片完整显示在特定的界面中
1、首先创建一个类继承ImageView,第一步当然是构造函数,关于AttributeSet相关点本章不涉及:
这里仅仅只是做初始化画笔和拿到图片的工作,
在自定义View的onMeasure、onLayout、onDraw等方法里面做new对象的操作。
因为实例化对象是会耗性能的,而这几个方法会被多次调用,所以需要将对象作为属性,在初始化的时候就实例化好对象,尽量不要在其中做复杂的操作或者new 新对象,频繁new 新对象会导致gc动作,也可能导致掉帧,造成内存溢出的问题
public CircleView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); }
private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); // 设置抗锯齿 mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.FILL);//实心 Drawable drawable = getDrawable(); if (drawable instanceof BitmapDrawable) { mBitmap = ((BitmapDrawable) drawable).getBitmap(); //拿到在xml中配置的src图片 } }
2.重写onDraw
@Override protected void onDraw(Canvas canvas) { if (mBitmap != null) {//如果没有配置会拿到空,需要对这种情况做判断 drawableCircle(canvas); } else { super.onDraw(canvas); } }
private void drawableCircle(Canvas canvas) { /** * shader 着色器,BitmapShader图像着色器,可以理解为图像本身就是着色的效果,也就是你画出来的内容(填充) */ BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);// 填充BitMap,bitmap,x,y轴空隙的填充方式 //得到bitmap和界面的比例,传入矩阵matrix,使图片大小适应界面大小 float scaleX = getWidth() / (float) mBitmap.getWidth(); float scaleY = getHeight() / (float) mBitmap.getHeight(); Matrix matrix = new Matrix(); matrix.setScale(scaleX, scaleY); // 传入x,y的比列 bitmapShader.setLocalMatrix(matrix); //给shard 着色器设置矩阵比列 mPaint.setShader(bitmapShader); // 给画笔设置着色器 canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, Math.min(getWidth() / 2f, getHeight() / 2f), mPaint); //圆心的坐标x和y, 半径,画笔 }
这样就画出圆形图像啦
下面是布局xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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=".MainActivity"> <com.example.CircleViewTest.CircleView // 只是把原先的imageView换成你自己重写的CircleView就好 android:layout_width="150dp" android:layout_height="150dp" android:scaleType="centerCrop" android:src="@drawable/hard" android:layout_margin="10dp" /> </LinearLayout>
效果