高级UI - Paint基本使用.高级渲染使用(最后实现放大镜效果)

Paint 基本使用

《Paint的方法主要可以抽象成两大类》:

		 1.1 负责设置获取图形绘制、路径相关的
			1.setStyle(Paint.Style style) 
			设置画笔样式,取值有
			Paint.Style.FILL :填充内部
			Paint.Style.FILL_AND_STROKE :填充内部和描边
			Paint.Style.STROKE :仅描边、
			注意STROKE、FILL_OR_STROKE与FILL模式下外轮廓的位置会扩大。
			2.setStrokeWidth(float width) 
			设置画笔宽度 
			3.setAntiAlias(boolean aa) 
			设置画笔是否抗锯齿 
			4.setStrokeCap(Paint.Cap cap) ------demo演示 
			设置线冒样式,取值有Cap.ROUND(圆形线冒)、Cap.SQUARE(方形线冒)、Paint.Cap.BUTT(无线冒) 
			注意:冒多出来的那块区域就是线帽!就相当于给原来的直线加上一个帽子一样,所以叫线帽 
			
			5.setStrokeJoin(Paint.Join join) ------ demo演示
			设置线段连接处样式,取值有:Join.MITER(结合处为锐角)、Join.Round(结合处为圆弧)、Join.BEVEL(结合处为直线) 
			
			6.setStrokeMiter(float miter) 
			设置笔画的倾斜度,90度拿画笔与30拿画笔,画出来的线条样式肯定是不一样的吧。(事实证明,根本看不出来什么区别好吗……囧……)
		
		
			void reset() 
			清空画笔复位。

			void set(Paint src) 
			设置一个外来Paint画笔。

			7.void setARGB(int a, int r, int g, int b) 
			int getAlpha() 
			void setAlpha(int a) 
			int getColor() 
			void setColor(int color) 
			获取与设置alpha值、颜色、ARGB等。

			final boolean isAntiAlias() 
			8.void setAntiAlias(boolean aa) 
			获取与设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢,一般会开启。设置后会平滑一些;

			final boolean isDither() 
			9.void setDither(boolean dither) 
			获取与设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满、图像更加清晰。
			
			10.setPathEffect(PathEffect effect);   
			* 设置绘制路径的效果,如点画线等 
			(1)、CornerPathEffect——圆形拐角效果 
				paint.setPathEffect(new CornerPathEffect(100));
				利用半径R=50的圆来代替原来两条直线间的夹角
			(2)、DashPathEffect——虚线效果 
				
				//画同一条线段,偏移值为15  
				paint.setPathEffect(new DashPathEffect(new float[]{20,10,50,100},15));
				intervals[]:表示组成虚线的各个线段的长度;整条虚线就是由intervals[]中这些基本线段循环组成的。比如,我们定义new float[] {20,10};那这个虚线段就是由两段线段组成的,第一个可见的线段长为20,每二个线段不可见,长度为10;
				phase:
				开始绘制的偏移值 
				
				.....
			
			11.setXfermode(Xfermode xfermode);   
			设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
			
			12.setMaskFilter(MaskFilter maskfilter);   
			设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等 
			
			13.setColorFilter(ColorFilter colorfilter);   
			设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
			14.setShader(Shader shader);   
			设置图像效果,使用Shader可以绘制出各种渐变效果   
   
			15.setShadowLayer(float radius ,float dx,float dy,int color);   
			在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色  
			

		1.2 负责设置获取文字相关的
		
			float getFontSpacing() 
			获取字符行间距。
			float getLetterSpacing() 
			void setLetterSpacing(float letterSpacing) 
			设置和获取字符间距
			
			final boolean isUnderlineText() 
			void setUnderlineText(boolean underlineText) 
			是否有下划线和设置下划线。
			final boolean isStrikeThruText() 
			void setStrikeThruText(boolean strikeThruText) 
			获取与设置是否有文本删除线。
			
			float getTextSize() 
			void setTextSize(float textSize) 
			获取与设置文字大小,注意:Paint.setTextSize传入的单位是px,TextView.setTextSize传入的单位是sp,注意使用时不同分辨率处理问题。
			
			Typeface getTypeface() 
			Typeface setTypeface(Typeface typeface) 
			获取与设置字体类型。Android默认有四种字体样式:BOLD(加粗)、BOLD_ITALIC(加粗并倾斜)、ITALIC(倾斜)、NORMAL(正常),我们也可以通过Typeface类来自定义个性化字体。
			
			float getTextSkewX() 
			void setTextSkewX(float skewX) 
			获取与设置文字倾斜,参数没有具体范围,官方推荐值为-0.25,值为负则右倾,为正则左倾,默认值为0。
			
			Paint.Align getTextAlign() 
			void setTextAlign(Paint.Align align) 
			获取与设置文本对齐方式,取值为CENTER、LEFT、RIGHT,也就是文字绘制是左边对齐、右边还是局中的。

			setSubpixelText(boolean subpixelText)
			固定的几个范围:320*480,480*800,720*1280,1080*1920等等;那么如何在同样的分辨率的显示器中增强显示清晰度呢?
			亚像素的概念就油然而生了,亚像素就是把两个相邻的两个像素之间的距离再细分,再插入一些像素,这些通过程序加入的像素就是亚像素。在两个像素间插入的像素个数是通过程序计算出来的,一般是插入两个、三个或四个。
			所以打开亚像素显示,是可以在增强文本显示清晰度的,但由于插入亚像素是通过程序计算而来的,所以会耗费一定的计算机性能。
			
			int breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth) 
			比如文本阅读器的翻页效果,我们需要在翻页的时候动态折断或生成一行字符串,这就派上用场了~

			
			
			计算指定参数长度能显示多少个字符,同时可以获取指定参数下可显示字符的真实长度,譬如:
			
			private static final String STR = "动脑ABCDEF";
			mPaint.setTextSize(50);
			float[] value = new float[1];
			int ret = mPaint.breakText(STR, true, 200, value);
			Log.i("YYYY", "breakText="+ret+", STR="+STR.length()+", value="+value[1]);
			//breakText=5, STR=8, value=195.0

			void getTextBounds(char[] text, int index, int count, Rect bounds) 
			void getTextBounds(String text, int start, int end, Rect bounds) 
			获取文本的宽高,通过bounds的Rect拿到整型。

			float measureText(String text) 
			float measureText(CharSequence text, int start, int end) 
			float measureText(String text, int start, int end) 
			float measureText(char[] text, int index, int count) 
			粗略获取文本的宽度,和上面的getTextBounds比较类似,返回浮点数。

			int getTextWidths(String text, int start, int end, float[] widths) 
			int getTextWidths(String text, float[] widths) 
			int getTextWidths(CharSequence text, int start, int end, float[] widths) 
			int getTextWidths(char[] text, int index, int count, float[] widths) 
			精确计算文字宽度,与上面两个类似。

Paint画文字文字的位置

Paint画笔来画文字  
Paint.FontMetrics  float类型

Paint.FontMetricsInt  int类型
里面有top,ascent,desent, bottom, leading这几个属性

top = top线的y坐标 - baseline线的y坐标
bottom = bottom线的y坐标 - baseline线的y坐标
ascent = ascent线的y坐标 - baseline线的y坐标
desent = desent线的y坐标 - baseline线的y坐标


1、A = B = (bottom - top)/2
bottom = baseline + FontMetrics.bottom
top = baseline + FontMetrics.top

---> A = B = (FontMetrics.bottom - FontMetrics.top)/ 2

2、C =  B - (bottom - baseline)
     =  B - FontMetrics.bottom

3、C = baseline - center
	
综上可得
baseline - center = (FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom

baseline = center +(FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom

Paint 高级渲染

Shader —着色器,Canvas的drawXXXX这个方法是画具体的形状,画笔的shader定义的就是图形的着色和外观

BitmapShader --位图图像渲染,用BitMap对绘制的图形进行渲染着色,简单来说是用图片对图形进行贴图
圆形头像,放大镜效果

TileMode 拉伸形式
	CLAMP --是拉伸最后一个像素铺满
	MIRROR ---是横向纵向不足处不断翻转镜像平铺
	REPEAT ---类似电脑壁纸,横向纵向不足的重复放置

LinearGradient --线性渲染
霓虹灯文字,倒影图片

SweepGradient ----渐变渲染/梯度渲染

	雷达扫描效果

RadialGradient ----环形渲染
水波纹效果

ComposeShader ----组合渲染

	可以自己发挥想象去组合一下

下面开始例子:

BitmapShader 例子 画一个圆形 原型头像

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        /**
         * TileMode.CLAMP 拉伸最后一个像素去铺满剩下的地方
         * TileMode.MIRROR 通过镜像翻转铺满剩下的地方。
         * TileMode.REPEAT 重复图片平铺整个画面(电脑设置壁纸)
         */
        /**
         * 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.用于绘制位图的x的平铺模式
         * @param tileY             The tiling mode for y to draw the bitmap in.用于绘制位图的Y的平铺模式
         */
        //BitmapShader使用  图片着色器
        BitmapShader bitmapShader = new BitmapShader(mBitMap, Shader.TileMode.MIRROR,Shader.TileMode.MIRROR);
        mPaint.setShader(bitmapShader);
        mPaint.setAntiAlias(true);//抗锯齿
        //圆形头像
        //参数 圆点的x,y, 半径, 画笔
        //画出原型头像
        canvas.drawCircle(mHeight / 2,mHeight / 2, mHeight / 2 ,mPaint);
        //椭圆
        //canvas.drawOval(new RectF(0 , 0, mWidth, mHeight),mPaint);

        //设置像素矩阵,来调整大小,为了解决宽高不一致的问题。
        float scale = Math.max(mWidth,mHeight) / Math.min(mWidth,mHeight);
        //矩阵使用 完成缩放
        Matrix matrix = new Matrix();
        matrix.setScale(scale,scale);
        bitmapShader.setLocalMatrix(matrix);
        //画出矩形
        canvas.drawRect(new Rect(0,500 , 1000, 1600),mPaint);
}

以上代码效果
mark


LinearGradient --线性渲染
可以做 霓虹灯文字,倒影图片

		 private int[] mColors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW};
		 
		 
		    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        
         /**线性渐变
         * x0, y0, 起始点
         *  x1, y1, 结束点
         * int[]  mColors, 中间依次要出现的几个颜色
         * float[] positions,数组大小跟colors数组一样大,中间依次摆放的几个颜色分别放置在那个位置上(参考比例从左往右)
         *    tile
         */
		LinearGradient linearGradient = new LinearGradient( 0, 0,800, 800, mColors, null, Shader.TileMode.CLAMP);
        // linearGradient = new LinearGradient(0, 0, 400, 400, mColors, null, Shader.TileMode.REPEAT);
		mPaint.setShader(linearGradient);
		canvas.drawRect(0, 0, 800, 800, mPaint);
        }
		

以上效果

mark


-RadialGradient 环形渐变,渲染
(水波纹效果)

mark

RadialGradient mRadialGradient = new RadialGradient(300, 300, 100, mColors, null, Shader.TileMode.REPEAT);
		mPaint.setShader(mRadialGradient);
		canvas.drawCircle(300, 300, 300, mPaint);

-SweepGradient 梯度渐变 ,梯度渲染
(可做雷达扫描效果)
mark

private int[] mColors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW};
 SweepGradient mSweepGradient = new SweepGradient(300, 300, mColors, null);
		mPaint.setShader(mSweepGradient);
		canvas.drawCircle(300, 300, 300, mPaint);

-组合渐变


放大镜效果

分析下如何做放大镜效果:

首先底部需要画原图,因为是放大镜所以需要获取放大后的图片,我这里是把整张图片放大,然后使用ShapeDrawable来画放大镜,通过矩阵变换和触摸事件来移动放大镜.

效果图:

mark
代码:


public class ZoomImageView1 extends View {

    //放大倍数
    private static final int FACTOR = 2;
    //放大镜的半径
    private static final int RADIUS = 100;
    // 原图
    private Bitmap mBitmap;
    // 放大后的图
    private Bitmap mBitmapScale;
    // 制作的圆形的图片(放大的局部),盖在Canvas上面
    private ShapeDrawable mShapeDrawable;

    private Matrix mMatrix;

    public ZoomImageView1(Context context) {
        super(context);
        //原图
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xyjy3);
        //赋值
        mBitmapScale = mBitmap;
        //创建放大后的图 参数 是X Y 轴放大的倍数
        mBitmapScale = Bitmap.createScaledBitmap(mBitmap, mBitmapScale.getWidth() * FACTOR,
                mBitmapScale.getHeight() * FACTOR, true);

        //使用BitmapShader
        BitmapShader bitmapShader = new BitmapShader(mBitmapScale, Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP);
//        Android中,利用ShapeDrawable来绘制图像,ShapeDrawable可以设置画笔的形状。通过geiPaint方可以得到Paint对象。
        mShapeDrawable = new ShapeDrawable(new OvalShape());//我这里做了个椭圆
        mShapeDrawable.getPaint().setShader(bitmapShader);//设置bitmapshader
        //setBounds 为可绘制的矩形指定一个边界矩形。这就是可拉的地方 当调用它的draw()方法时将会绘制。
        mShapeDrawable.setBounds(0, 0, RADIUS * 2, RADIUS * 2);

        mMatrix = new Matrix();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 1、画原图
        canvas.drawBitmap(mBitmap, 0, 0, null);

        // 2、画放大镜的图
        mShapeDrawable.draw(canvas);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        //实际上是平移放大后的图片
        // setTranslate方法 : 将矩阵转换为(dx,dy), 这里的作用将放大的图片往相反的方向挪动
        mMatrix.setTranslate(RADIUS - x * FACTOR, RADIUS - y * FACTOR);
        //设置着色器的本地矩阵。传递null将重置着色器
        //矩阵的身份。
        //参数着色器的新本地矩阵,或空来指定标识
        mShapeDrawable.getPaint().getShader().setLocalMatrix(mMatrix);
        // 切出手势区域点位置的圆
        mShapeDrawable.setBounds(x - RADIUS, y - RADIUS, x + RADIUS, y + RADIUS);
        invalidate();
        return true;
    }
}

LinearGradient 线性渲染-> 霓虹灯文字效果

原理: 在文字上面有一层线性渲染.

package com.dongnao.lsn4_paint_gradient;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * @author liuml
 * @explain
 * @time 2018/1/9 15:18
 */

@SuppressLint("AppCompatCustomView")
public class LinearGradientTextView1 extends TextView {

    private TextPaint mPaint;

    private LinearGradient mLinearGradient;
    private Matrix mMatrix;

    private float mTranslate;
    private float DELTAX = 20;



    public LinearGradientTextView1(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public LinearGradientTextView1(Context context) {
        super(context);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //在onSizeChanged 中

        //拿到TextView的画笔
        mPaint = getPaint();
        //获取文本
        String text = getText().toString();
        float textwith = mPaint.measureText(text);
        //一次高亮三个文字 获取三个文字的宽度
        int gradientSize = (int) (textwith / text.length() * 3);

        /**
         * 创建一个在直线上绘制线性渐变的着色器。
         @param x0是梯度线起始点的x坐标
         @param y0是梯度线起始点的y坐标
         @param x1是梯度线末端的x坐标
         @param y1是梯度线末端的y坐标
         @param 颜色颜色分布沿渐变线
         @param 位置可能是零,相对位置(0 . .颜色数组中的每一个对应的颜色,如果这是null,那么颜色就会沿着梯度线均匀分布
         @param 平铺的着色模式
         */
        //改变的是透明度  最中间的是白色 然后改变两边的透明度.
        //颜色数组  gradientSize 放在x0处 是让起始点放在外面
        mLinearGradient = new LinearGradient(-gradientSize, 0, 0, 0,
                new int[]{0x22ffffff, 0xffffffff, 0x22ffffff},
                null, Shader.TileMode.CLAMP
        );

        //设置到画笔中
        mPaint.setShader(mLinearGradient);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //在onDraw里面 不断改变
        mTranslate += DELTAX;
        float textWidth = getPaint().measureText(getText().toString());
        //如果到头了需要改变 超过文本长度或者回到起始点.需要返回来
        if(mTranslate>textWidth+1|| mTranslate < 1){
            //需要往相反的方向运动  给个负值就行
            DELTAX = -DELTAX;
        }


        mMatrix = new Matrix();
//        将矩阵转换为(dx,dy)
        mMatrix.setTranslate(mTranslate,0);
        //设置着色器的本地矩阵。传递null将重置着色器 矩阵的身份。
        mLinearGradient.setLocalMatrix(mMatrix);
        //延时
        postInvalidateDelayed(50);

    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    android:background="#000"
    tools:context="com.dongnao.lsn4_paint_gradient.MainActivity">

   <!-- <com.dongnao.lsn4_paint_gradient.MyGradientView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />-->
    <com.dongnao.lsn4_paint_gradient.LinearGradientTextView1
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:textColor="#666666"
        android:text="六道对穿肠自定义霓虹灯文字效果"/>

</android.support.constraint.ConstraintLayout>

下面是效果图

mark

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值