赞
踩
https://blog.csdn.net/aigestudio/article/details/41799811
构造方法
/**
* Call this to create a new shader that will draw with a bitmap.
*
* @param bitmap The bitmap to use inside the shader
* @param tileX The tiling mode for x to draw the bitmap in.
* @param tileY The tiling mode for y to draw the bitmap in.
*/
public BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY) {
this(bitmap, tileX.nativeInt, tileY.nativeInt);
}
设置BitmapShader之前
设置BitmapShader之后
private fun drawBitmapShaderView(canvas: Canvas) { val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG) .apply { this.color = Color.RED this.strokeWidth = 5F } val bitmap = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher_round) //paint.setShader(BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)) canvas.drawColor(Color.BLACK) // 绘制矩形' val width = 300F; val height = 170F var left = 0F; var top = 20F; var right = left + width; var bottom = top + height canvas.drawRect(left, top, right, bottom, paint) val tiles = arrayListOf<Shader.TileMode>( Shader.TileMode.CLAMP, Shader.TileMode.MIRROR, Shader.TileMode.REPEAT ) fun getStringText(tileMode: Shader.TileMode): String { return when (tileMode) { Shader.TileMode.CLAMP -> "Shader.TileMode.CLAMP" Shader.TileMode.MIRROR -> "Shader.TileMode.MIRROR" Shader.TileMode.REPEAT -> "Shader.TileMode.REPEAT" else -> "" } } // Shader.TileMode.CLAMP for (tileX in tiles) { for (tileY in tiles) { left = left.plus(30F) top = top.plus(height + 10) right = left.plus(width) bottom = top + height paint.shader = BitmapShader(bitmap, tileX, tileY) paint.color = Color.BLUE canvas.drawRect(left, top, right, bottom, paint) paint.color = Color.YELLOW canvas.drawLine(0F, top, 1000F, top, paint) paint.color = Color.RED canvas.drawLine(0F, bottom, 1000F, bottom, paint) //绘制文字 paint.color =Color.GREEN paint.textSize = 38F paint.shader = null canvas.drawText("${getStringText(tileX)}\n${getStringText(tileY)}", 0F, bottom, paint) } } }
mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
REPEAT 是重复的意思, MIRROR就是镜像的意思
mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.MIRROR));
大家可以看到图像分为两部分左边呢Y轴镜像了,而右边像是被拉伸了一样怪怪的!其实CLAMP的意思就是边缘拉伸的意思,比如上图中左边Y轴镜像了,而右边会紧挨着左边将图像边缘上的第一个像素沿X轴复制!
var posX = 0F var posY = 0F override fun onTouchEvent(event: MotionEvent?): Boolean { if (event?.action == MotionEvent.ACTION_MOVE) { posX = event.x posY = event.y invalidate() } return true } private fun drawBrickView(canvas: Canvas) { // 圆边 val mStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG) .apply { this.color = Color.BLACK this.style = Paint.Style.STROKE this.strokeWidth = 5F } val mFillPaint = Paint() val decodeResource = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher) mFillPaint.shader = BitmapShader(decodeResource, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT) //设置画笔背景色 canvas.drawColor(Color.DKGRAY) //绘制圆和描边 canvas.drawCircle(posX, posY, 200F, mFillPaint) canvas.drawCircle(posX, posY, 200F, mStrokePaint) }
线性渐变
mPaint.setShader(new LinearGradient(left, top, right, bottom, Color.RED, Color.YELLOW, Shader.TileMode.REPEAT));
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
/*
参数虽多其实很好理解x0和y0表示渐变的起点坐标而x1和y1则表示渐变的终点坐标,这两点都是相对于屏幕坐标系而言的,而color0和color1则表示起点的颜色和终点的颜色,这些即便是213也能懂 - - ……Shader.TileMode上面我们给的是REPEAT重复但是并没有任何效果,这时因为我们渐变的起点和终点都落在了图形的两端,整个渐变shader已经填充了图形所以不起作用,如果我们改改,把终点坐标变一下:
*/
mPaint.setShader(new LinearGradient(left, top, right - RECT_SIZE, bottom - RECT_SIZE, Color.RED, Color.YELLOW, Shader.TileMode.REPEAT));
LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile)
mPaint.setShader(new LinearGradient(left, top, right, bottom, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE }, new float[] { 0, 0.1F, 0.5F, 0.7F, 0.8F }, Shader.TileMode.MIRROR));
mPaint.setShader(new LinearGradient(left, top, right, bottom, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE }, null, Shader.TileMode.MIRROR));
private fun drawReflectView(canvas: Canvas) { val mSrcBitmap = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher) //实例化一个矩阵 val matrix = Matrix().apply { this.setScale(1F, -1F) } //生成倒影图 val mRefBitmap = Bitmap.createBitmap(mSrcBitmap, 0, 0, mSrcBitmap.width, mSrcBitmap.height, matrix, true) val x = canvas.width.div(2) - mSrcBitmap.width.div(2) val y = canvas.height.div(2) - mSrcBitmap.height.div(2) val mPain = Paint() mPain.shader = LinearGradient( x.toFloat() , (y + mSrcBitmap.height).toFloat() , x.toFloat() , (y + mSrcBitmap.height + mSrcBitmap.height / 4).toFloat() , 0xAA000000.toInt() , Color.TRANSPARENT , Shader.TileMode.CLAMP ) val mXfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN) canvas.drawColor(Color.BLACK) canvas.drawBitmap(mSrcBitmap, x.toFloat(), y.toFloat(), null) val saveLayer = canvas.saveLayer( x.toFloat() , (y + mSrcBitmap.getHeight()).toFloat() , (x + mRefBitmap.getWidth()).toFloat() , (y + mSrcBitmap.getHeight() * 2).toFloat() , null , Canvas.ALL_SAVE_FLAG ) canvas.drawBitmap( mRefBitmap , x.toFloat() , (y + mSrcBitmap.height).toFloat() , null ) mPain.setXfermode(mXfermode) canvas.drawRect( x.toFloat() , (y + mSrcBitmap.height).toFloat() , (x + mRefBitmap.width).toFloat() , (y + mSrcBitmap.height * 2).toFloat() , mPain ) mPain.setXfermode(null) canvas.restoreToCount(saveLayer) }
SweepGradient(float cx, float cy, int color0, int color1)
mPaint.setShader(new SweepGradient(screenX, screenY, Color.RED, Color.YELLOW));
SweepGradient(float cx, float cy, int[] colors, float[] positions)
mPaint.setShader(new SweepGradient(screenX, screenY, new int[] { Color.GREEN, Color.WHITE, Color.GREEN }, null));
RadialGradient (float centerX, float centerY, float radius, int centerColor, int edgeColor, Shader.TileMode tileMode)
RadialGradient (float centerX, float centerY, float radius, int centerColor, int edgeColor, Shader.TileMode tileMode)
原图
修改后的
private fun DreamEffectView(canvas: Canvas) { //获取位图 val mBitmap = BitmapFactory.decodeResource(resources, R.drawable.beatuful) //实例化混合模式 val mXfermode = PorterDuffXfermode(PorterDuff.Mode.SCREEN) val x = (canvas.width - mBitmap.width).div(2).toFloat() val y = (canvas.height - mBitmap.height).div(2).toFloat() //实例化画笔 val mBitmapPaint = Paint(Paint.ANTI_ALIAS_FLAG) //去饱和、提亮、色相矫正 mBitmapPaint.colorFilter = ColorMatrixColorFilter(floatArrayOf(0.8587F, 0.2940F, -0.0927F, 0F, 6.79F, 0.0821F, 0.9145F, 0.0634F, 0F, 6.79F, 0.2019F, 0.1097F, 0.7483F, 0F, 6.79F, 0F, 0F, 0F, 1F, 0F)) canvas.drawColor(Color.BLACK) //新建图层 val saveLayer = canvas.saveLayer( x, y, x + mBitmap.width, y + mBitmap.height, null, Canvas.ALL_SAVE_FLAG ) //绘制混合颜色 canvas.drawColor(0xcc1c093e.toInt()) //设置混合模式 mBitmapPaint.xfermode = mXfermode //绘制位图 canvas.drawBitmap(mBitmap, x, y, mBitmapPaint) //环元混合模式 mBitmapPaint.xfermode = null //还原画布 canvas.restoreToCount(saveLayer) }
private fun DreamEffectViewRadialGradient(canvas: Canvas) { //获取位图 val mBitmap = BitmapFactory.decodeResource(resources, R.drawable.beatuful) //实例化混合模式 val mXfermode = PorterDuffXfermode(PorterDuff.Mode.SCREEN) val x = (canvas.width - mBitmap.width).div(2).toFloat() val y = (canvas.height - mBitmap.height).div(2).toFloat() //实例化画笔 val mBitmapPaint = Paint(Paint.ANTI_ALIAS_FLAG) //去饱和、提亮、色相矫正 mBitmapPaint.colorFilter = ColorMatrixColorFilter(floatArrayOf(0.8587F, 0.2940F, -0.0927F, 0F, 6.79F, 0.0821F, 0.9145F, 0.0634F, 0F, 6.79F, 0.2019F, 0.1097F, 0.7483F, 0F, 6.79F, 0F, 0F, 0F, 1F, 0F)) //s实例化Shadaer图形的画笔 val mShaderPaint = Paint(); //设置径向渐变,渐变中心当然是图标的中心,也是屏幕中心,渐变的半径我们直接拿图片的高度但是稍微小一点 //中心颜色为透明而边缘颜色为黑色 mShaderPaint.shader = RadialGradient( canvas.width.div(2).toFloat() , canvas.height.div(2).toFloat() , mBitmap.height.times(7).div(8).toFloat() , Color.TRANSPARENT , Color.BLACK , Shader.TileMode.CLAMP ) canvas.drawColor(Color.BLACK) //新建图层 val saveLayer = canvas.saveLayer( x, y, x + mBitmap.width, y + mBitmap.height, null, Canvas.ALL_SAVE_FLAG ) //绘制混合颜色 canvas.drawColor(0xcc1c093e.toInt()) //设置混合模式 mBitmapPaint.xfermode = mXfermode //绘制位图 canvas.drawBitmap(mBitmap, x, y, mBitmapPaint) //环元混合模式 mBitmapPaint.xfermode = null //还原画布 canvas.restoreToCount(saveLayer) }
ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode)
ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
public class DreamEffectView extends View { private Paint mBitmapPaint, mShaderPaint;// 位图画笔和Shader图形的画笔 private Bitmap mBitmap, darkCornerBitmap;// 源图的Bitmap和我们自己画的暗角Bitmap private PorterDuffXfermode mXfermode;// 图形混合模式 private int x, y;// 位图起点坐标 private int screenW, screenH;// 屏幕宽高 public DreamEffectView(Context context, AttributeSet attrs) { super(context, attrs); // 初始化资源 initRes(context); // 初始化画笔 initPaint(); } /** * 初始化资源 * * @param context * 丢你螺母 */ private void initRes(Context context) { // 获取位图 mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.gril); // 实例化混合模式 mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SCREEN); screenW = MeasureUtil.getScreenSize((Activity) context)[0]; screenH = MeasureUtil.getScreenSize((Activity) context)[1]; x = screenW / 2 - mBitmap.getWidth() / 2; y = screenH / 2 - mBitmap.getHeight() / 2; } /** * 初始化画笔 */ private void initPaint() { // 实例化画笔 mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 去饱和、提亮、色相矫正 mBitmapPaint.setColorFilter(new ColorMatrixColorFilter(new float[] { 0.8587F, 0.2940F, -0.0927F, 0, 6.79F, 0.0821F, 0.9145F, 0.0634F, 0, 6.79F, 0.2019F, 0.1097F, 0.7483F, 0, 6.79F, 0, 0, 0, 1, 0 })); // 实例化Shader图形的画笔 mShaderPaint = new Paint(); // 根据我们源图的大小生成暗角Bitmap darkCornerBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888); // 将该暗角Bitmap注入Canvas Canvas canvas = new Canvas(darkCornerBitmap); // 计算径向渐变半径 float radiu = canvas.getHeight() * (2F / 3F); // 实例化径向渐变 RadialGradient radialGradient = new RadialGradient(canvas.getWidth() / 2F, canvas.getHeight() / 2F, radiu, new int[] { 0, 0, 0xAA000000 }, new float[] { 0F, 0.7F, 1.0F }, Shader.TileMode.CLAMP); // 实例化一个矩阵 Matrix matrix = new Matrix(); // 设置矩阵的缩放 matrix.setScale(canvas.getWidth() / (radiu * 2F), 1.0F); // 设置矩阵的预平移 matrix.preTranslate(((radiu * 2F) - canvas.getWidth()) / 2F, 0); // 将该矩阵注入径向渐变 radialGradient.setLocalMatrix(matrix); // 设置画笔Shader mShaderPaint.setShader(radialGradient); // 绘制矩形 canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mShaderPaint); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.BLACK); // 新建图层 int sc = canvas.saveLayer(x, y, x + mBitmap.getWidth(), y + mBitmap.getHeight(), null, Canvas.ALL_SAVE_FLAG); // 绘制混合颜色 canvas.drawColor(0xcc1c093e); // 设置混合模式 mBitmapPaint.setXfermode(mXfermode); // 绘制位图 canvas.drawBitmap(mBitmap, x, y, mBitmapPaint); // 还原混合模式 mBitmapPaint.setXfermode(null); // 还原画布 canvas.restoreToCount(sc); // 绘制我们画好的径向渐变图 canvas.drawBitmap(darkCornerBitmap, x, y, null); } }
matrix的
<com.example.customview.MatrixImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
public class MatrixImageView extends androidx.appcompat.widget.AppCompatImageView { private static final int MODE_NONE = 0x00123;// 默认的触摸模式 private static final int MODE_DRAG = 0x00321;// 拖拽模式 private static final int MODE_ZOOM = 0x00132;// 缩放or旋转模式 private int mode;// 当前的触摸模式 private float preMove = 1F;// 上一次手指移动的距离 private float saveRotate = 0F;// 保存了的角度值 private float rotate = 0F;// 旋转的角度 private float[] preEventCoor;// 上一次各触摸点的坐标集合 private PointF start, mid;// 起点、中点对象 private Matrix currentMatrix, savedMatrix;// 当前和保存了的Matrix对象 private Context mContext;// Fuck…… public MatrixImageView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; // 初始化 init(); } /** * 初始化 */ private void init() { /* * 实例化对象 */ currentMatrix = new Matrix(); savedMatrix = new Matrix(); start = new PointF(); mid = new PointF(); // 模式初始化 mode = MODE_NONE; /* * 设置图片资源 */ Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.background); bitmap = Bitmap.createScaledBitmap(bitmap, 1000, 1000, true); setImageBitmap(bitmap); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN:// 单点接触屏幕时 savedMatrix.set(currentMatrix); start.set(event.getX(), event.getY()); mode = MODE_DRAG; preEventCoor = null; break; case MotionEvent.ACTION_POINTER_DOWN:// 第二个点接触屏幕时 preMove = calSpacing(event); if (preMove > 10F) { savedMatrix.set(currentMatrix); calMidPoint(mid, event); mode = MODE_ZOOM; } preEventCoor = new float[4]; preEventCoor[0] = event.getX(0); preEventCoor[1] = event.getX(1); preEventCoor[2] = event.getY(0); preEventCoor[3] = event.getY(1); saveRotate = calRotation(event); break; case MotionEvent.ACTION_UP:// 单点离开屏幕时 case MotionEvent.ACTION_POINTER_UP:// 第二个点离开屏幕时 mode = MODE_NONE; preEventCoor = null; break; case MotionEvent.ACTION_MOVE:// 触摸点移动时 /* * 单点触控拖拽平移 */ if (mode == MODE_DRAG) { currentMatrix.set(savedMatrix); float dx = event.getX() - start.x; float dy = event.getY() - start.y; currentMatrix.postTranslate(dx, dy); } /* * 两点触控拖放旋转 */ else if (mode == MODE_ZOOM && event.getPointerCount() == 2) { float currentMove = calSpacing(event); currentMatrix.set(savedMatrix); /* * 指尖移动距离大于10F缩放 */ if (currentMove > 10F) { float scale = currentMove / preMove; currentMatrix.postScale(scale, scale, mid.x, mid.y); } /* * 保持两点时旋转 */ if (preEventCoor != null) { rotate = calRotation(event); float r = rotate - saveRotate; currentMatrix.postRotate(r, getMeasuredWidth() / 2, getMeasuredHeight() / 2); } } break; } setImageMatrix(currentMatrix); return true; } /** * 计算两个触摸点间的距离 */ private float calSpacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float) Math.sqrt(x * x + y * y); } /** * 计算两个触摸点的中点坐标 */ private void calMidPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } /** * 计算旋转角度 * * @return 角度值 */ private float calRotation(MotionEvent event) { double deltaX = (event.getX(0) - event.getX(1)); double deltaY = (event.getY(0) - event.getY(1)); double radius = Math.atan2(deltaY, deltaX); return (float) Math.toDegrees(radius); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。