zoukankan      html  css  js  c++  java
  • 高级UI-高级渲染

    在使用了Panit画笔之后,可以对其进行渲染,从而达到更加人性化的方式

    渲染分类

    按常用渲染方式可以分为以下几种:

    • BimapShader位图的图像渲染器
    • LinearGradient线性渲染
    • RadialGradient环形渲染:水波纹效果,充电水波纹扩散效果、调色板
    • SweepGradient梯度渲染(扫描渲染):微信等雷达扫描效果,手机卫士垃圾扫描
    • ComposeShader组合渲染

    BimapShader

    首先来研究下BimapShader是怎么使用的
    一般来说绘制位图使用这种方式

    canvas.drawBitmap(bitmap, 0, 0, paint);
    

    这样就直接将位图绘制在界面上,那么使用以后,可以设置三种系统模式,设置完以后画笔添加Shader,然后就可以使用位图渲染器了
    这样的设置运用于图片宽高小于给定的宽高的处理方式

    //CLAMP 拉伸最后一个像素填满
    //MIRROR 镜像翻转填满
    //REPEAT 重复图片平铺填满
    bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
    paint.setShader(bitmapShader);
    //绘制边界
    canvas.drawRect(new Rect(0, 0, 800, 800), paint);
    

    其常用的场景其中一个就是绘制用户圆形头像,其中width为bitmap的宽

    canvas.drawCircle(width / 2, width / 2, width / 2, paint);
    

    这样的设置会以图片的中心点切出一个圆,那么如果图片方形,切出的图片效果还可以,那么如果为矩形,要么设置时候切为方形,要么继续处理,其思路就是对短边进行拉伸,但一般不建议那么做,那样做图片就变形了,其拉伸代码如下

    float scale = (float) Math.max(width, height) / Math.min(width, height);
    Matrix matrix = new Matrix();
    matrix.setScale(scale, scale);
    bitmapShader.setLocalMatrix(matrix);
    paint.setShader(bitmapShader);
    canvas.drawCircle(Math.min(width, height) / 2f, scale * Math.max(width, height) / 2f,
            Math.max(width, height) / 2f, paint)
    

    当然也可以绘制椭圆

    canvas.drawOval(new RectF(0, 0, width, height), paint);
    

    另外通过shapeDrawable也可以实现

    ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
    shapeDrawable.getPaint().setShader(bitmapShader);
    shapeDrawable.setBounds(0, 0, width, width);
    shapeDrawable.draw(canvas);
    

    LinearGradient

    线性渲染,其实就是一种线性渐变,可以实现各种炫酷的过度效果
    LinearGradient的参数:
    x0, y0:起始点
    x1, y1:结束点
    int[] colors:中间依次要出现的几个颜色
    float[] positions:数组大小跟colors数组一样大,中间依次摆放的几个颜色分别放置在那个位置上(参考比例从左往右)
    TileMode tile:CLAMP,MIRROR和REPEAT

    LinearGradient linearGradient = new LinearGradient(0, 0, 500, 0, colors, null, Shader.TileMode.CLAMP);
    paint.setShader(linearGradient);
    paint.setStrokeWidth(20);
    canvas.drawLine(0, 0, 500, 0, paint);
    

    其效果就是画出一条渐变色的彩带,和调色板类似

    RadialGradient

    环形渲染可以做出很多炫酷的效果,水波纹,充电波动等等,都是环形渲染做出来的

    RadialGradient radialGradient = new RadialGradient(100, 100, 50, colors, null, Shader.TileMode.CLAMP);
    paint.setShader(radialGradient);
    canvas.drawCircle(100, 100, 50, paint);
    

    SweepGradient

    类似于色度盘

    SweepGradient sweepGradient = new SweepGradient(100, 100, colors, null);
    paint.setShader(sweepGradient);
    canvas.drawCircle(100, 100, 50, paint);
    

    ComposeShader

    组合多个渲染方式,其参数为多个

    ComposeShader composeShader = new ComposeShader(radialGradient, sweepGradient, PorterDuff.Mode.SRC_OVER);
    paint.setShader(composeShader);
    canvas.drawCircle(100, 100, 50, paint);
    

    参数示例图如下
    高级渲染-组合渲染参数
    具体代码参阅Android示例源代码Xfermodes.java
    参数意义为:

    • PorterDuff.Mode.CLEAR 所绘制不会提交到画布上
    • PorterDuff.Mode.SRC 显示上层绘制图片
    • PorterDuff.Mode.DST 显示下层绘制图片
    • PorterDuff.Mode.SRC_OVER 正常绘制显示,上下层绘制叠盖
    • PorterDuff.Mode.DST_OVER 上下层都显示。下层居上显示
    • PorterDuff.Mode.SRC_IN 取两层绘制交集。显示上层
    • PorterDuff.Mode.DST_IN 取两层绘制交集。显示下层
    • PorterDuff.Mode.SRC_OUT 取上层绘制非交集部分
    • PorterDuff.Mode.DST_OUT 取下层绘制非交集部分
    • PorterDuff.Mode.SRC_ATOP 取下层非交集部分与上层交集部分
    • PorterDuff.Mode.DST_ATOP 取上层非交集部分与下层交集部分
    • PorterDuff.Mode.XOR 异或:去除两图层交集部分
    • PorterDuff.Mode.DARKEN 取两图层全部区域,交集部分颜色加深
    • PorterDuff.Mode.LIGHTEN 取两图层全部,点亮交集部分颜色
    • PorterDuff.Mode.MULTIPLY 取两图层交集部分叠加后颜色
    • PorterDuff.Mode.SCREEN 取两图层全部区域,交集部分变为透明色

    图像示例

    //线性渲染
    LinearGradient linearGradient = new LinearGradient(200, 100, 600, 100, colors, null, Shader.TileMode.CLAMP);
    paint.setShader(linearGradient);
    paint.setStrokeWidth(50);
    canvas.drawLine(200, 100, 600, 100, paint);
    
    //环形渲染
    RadialGradient radialGradient = new RadialGradient(400, 400, 200, colors, null, Shader.TileMode.CLAMP);
    paint.setShader(radialGradient);
    canvas.drawCircle(400, 400, 200, paint);
    
    //梯度渲染
    SweepGradient sweepGradient = new SweepGradient(400, 1000, colors, null);
    paint.setShader(sweepGradient);
    canvas.drawCircle(400, 1000, 200, paint);
    

    从上到下依次是线性渲染,环形渲染和梯度渲染
    高级渲染-示例样张

    例子:歌词的显示效果

    自定义一个TextView,然后在绘制时候通过矩阵变换,不断设置线性渐变的位置,从而达到效果

    public class LinearGradientTextView extends TextView {
        private TextPaint paint;
        private float translateX;
        private LinearGradient linearGradient;
        private Matrix matrix;
        private float textWidth;
        private float deltaX = 10;
    
        public LinearGradientTextView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            paint = getPaint();
            //获得文字宽度,即为渲染宽度
            String text = getText().toString();
            textWidth = paint.measureText(text);
            int gradientSize = (int) (textWidth / text.length());
            linearGradient = new LinearGradient(2 * gradientSize, 0, 0, 0,
                    new int[]{0x0FFFFFFF, 0xFFFFFFFF, 0x0FFFFFFF}, null, Shader.TileMode.CLAMP);
            paint.setShader(linearGradient);
            matrix = new Matrix();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            translateX += deltaX;
            if (translateX > textWidth + 1 || translateX < 1) {
                deltaX = -deltaX;
            }
            //矩阵变换
            matrix.setTranslate(translateX, 0);
            linearGradient.setLocalMatrix(matrix);
            postInvalidate();
        }
    }
    

    布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/darker_gray">
    
        <com.cj5785.shadertest.LinearGradientTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="这段文字用来测试线性渐变的效果"
            android:textColor="@android:color/black"
            android:textSize="24sp" />
    
    </LinearLayout>
    

    效果图如下
    高级渲染-歌词效果

    例子:放大镜

    这里自定义一个View,用来承载图片以及局部放大

    public class ZoomImageView extends View {
        private Bitmap bitmap;
        private ShapeDrawable drawable;
        //缩放的倍数
        private static final int FACTOR = 2;
        //缩放的半径
        private static final int RADIUS = 100;
        private Matrix localM = new Matrix();
    
        public ZoomImageView(Context context) {
            super(context);
            bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
            //缩放图片
            Bitmap bmp = bitmap;
            bmp = Bitmap.createScaledBitmap(bmp, bmp.getWidth() * FACTOR, bmp.getHeight() * FACTOR, true);
            //切出矩形区域
            drawable = new ShapeDrawable(new OvalShape());
            BitmapShader shader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            drawable.getPaint().setShader(shader);
            drawable.setBounds(0, 0, RADIUS * 2, RADIUS * 2);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawBitmap(bitmap, 0, 0, null);
            drawable.draw(canvas);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            //控制手指移动
            localM.setTranslate(RADIUS - x * FACTOR, RADIUS - y * FACTOR);
            drawable.getPaint().getShader().setLocalMatrix(localM);
            drawable.setBounds(x - RADIUS, y - RADIUS, x + RADIUS, y + RADIUS);
            invalidate();
            return true;
        }
    }
    

    调用的时候直接设置这个View

    public class ZoomImageActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ZoomImageView zoomImageView = new ZoomImageView(this);
            setContentView(zoomImageView);
    //        setContentView(R.layout.activity_zoom_image);
        }
    }
    

    效果如下
    高级渲染-放大镜

  • 相关阅读:
    Qt uchar * 转 QImage
    WIN10 蓝牙连接音箱之后,音量调节无效,音量从1-100,声音一样大,都是最大声,可以静音(解决方案)
    OpenGL 保存bmp图像
    Qt 使用自带的OpenGL模块开发程序
    OpenCVSharp介绍
    OpenCV介绍
    OpenAL介绍
    OpenCL介绍
    OpenGL介绍
    Qt 无法打开包括文件:“QGLWidget”: No such file or directory
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664583.html
Copyright © 2011-2022 走看看