关于ondraw你该知道的(二)

目录

1.变形矩阵Matrix

0)简介

1)主要函数

2)示例

3)set()、post()、pre()函数

2.drawbitmapmesh像素块分析

2.Shader渲染器

1)图像渲染———BitmapShader

2)LinearGradient——–线性渲染

3)RadialGradient——–环形渲染

4)SweepGradient——–扫描渲染

5)ComposeShader——组合渲染

3.PathEffect

1)简介

2)示例


1.变形矩阵Matrix

0)简介

原理:也是一个矩阵,矩阵运算类似于ColorMatrix,区别是Matrix是一个3×3的矩阵,对图形的变化也是通过在初始矩阵的基础上修改矩阵元素值,从而达到修改图像的目的。

1)主要函数

通过Matrix可以图像进行平移,旋转,缩放,错切等操作。

旋转:Matrix.setRotate()

平移:Matrix.setTranslate()

缩放:Matrix.setScale()

错切:Matrix.setSkew()

这些方法操作的都是像素点,比如缩放为原来的0.5,效果就是将每个像素点的X坐标变成原来的0.5倍。

2)示例

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.draw_img);
        Matrix matrix = new Matrix();
        canvas.drawBitmap(mBitmap, matrix, paint);
        //平移
        matrix.setTranslate(0, 150);
        canvas.drawBitmap(mBitmap, matrix, paint);
    }

https://img-blog.csdnimg.cn/20190306152840879.png

可以看到原图,将平移后的效果绘制

3)set()、post()、pre()函数

set:重置矩阵中所有值,只保存set修改图像的操作

post:将修改图像的操作插入到一系列操作的队尾

pre:将修改图像的操作插入到一系列操作的队首

举个例子:

Matrix m = new Matrix();
m.preScale(0,0);   //①  
m.postScale(2, 2);    //②
m.preTranslate(1, 1); // ③ 

执行顺序为:③-①-②

2.drawbitmapmesh像素块分析

图中横竖交叉的线,将图形分成N块,我们可以通过改变横竖线的交叉点坐标,从而达到改变像素块的效果。

https://upload-images.jianshu.io/upload_images/1856419-29381107dcd149af.png?imageMogr2/auto-orient/

看看主要函数,如下:

drawBitmapMesh(Bitmap bitmap, 
               int meshWidth, 
               int meshHeight,
               float[] verts,
               int vertOffset, 
               int[] colors, 
               int colorOffset,
               Paint paint)

meshWidth:需要的横向网格数目

meshHeight:需要的纵向网格数目

verts:网格交叉点的坐标数组

vertOffset:数组中跳过的坐标对(x,y)的数目

主要看看verts:它的元素组成形式是(x1,y1,x2,y2,x3,y3.....),所以数组长度为偶数。

可以参考一些效果,实现图形的扭曲,变化等。

https://blog.csdn.net/qq_38261174/article/details/80042258

https://www.jianshu.com/p/51d8dd99d27d

2.Shader渲染器

可以用来实现一系列的渐变、渲染效果。

1)图像渲染———BitmapShader

效果:最终paint画的形状,就是渲染出来的图形

https://img-blog.csdnimg.cn/20190306161427943.png

代码:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Bitmap bitmap =BitmapFactory.decodeResource(getResources(),R.mipmap.draw_img);
        int radius = bitmap.getHeight()/2;
        //画笔
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        //BitmapShader设置给paint
        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT,Shader.TileMode.REPEAT);
        paint.setShader(bitmapShader);
        //画圆
        canvas.drawCircle(radius, radius, radius, paint);
    }

说下函数BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)的参数:

bitmap:渲染的图形

tileX:表示在位图上X方向渲染器平铺模式(TileMode) 

tileY:表示在位图上Y方向渲染器平铺模式(TileMode),与tileX同理

再看看TileMode的分类效果:

REPEAT :重复(效果为横向或纵向不断重复显示bitmap )

MIRROR :镜像(效果为横向或纵向不断翻转重复 )

CLAMP:拉伸(效果为横向或纵向拉伸图片在该方向的最后一个像素,区分电脑屏保的拉伸)

2)LinearGradient——–线性渲染

重点:需要指定渐变的起始颜色

效果:

https://img-blog.csdnimg.cn/20190306162540959.png

代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int radius = 100;
        //画笔
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        //Shader设置给paint
        paint.setShader(new LinearGradient(0,0,radius/2,radius/2,Color.RED,Color.BLUE,Shader.TileMode.REPEAT));
        //画圆
        canvas.drawCircle(radius, radius, radius, paint);
    }

看看LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, TileMode tile)参数:

x0:是梯度线起始点的x坐标

y0:是梯度线起始点的y坐标

x1:是梯度线末端的x坐标

y1:是梯度线末端的y坐标

color0:渐变线开始的颜色。

color1:渐变线末端的颜色。

tile:平铺着色器的平铺模式

3)RadialGradient——–环形渲染

效果:

https://img-blog.csdnimg.cn/20190306163654327.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

代码:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //1.圆心X坐标2.Y坐标3.半径 4.颜色数组 5.相对位置数组,可为null 6.渲染器平铺模式
        RadialGradient mRadialGradient = new RadialGradient(240, 240, 200, new int[] {
                Color.YELLOW, Color.BLUE, Color.TRANSPARENT, Color.RED }, null,
                Shader.TileMode.REPEAT);
        Paint mPaint = new Paint();
        // 绘制环形渐变
        mPaint.setShader(mRadialGradient);
        // 第一个,第二个参数表示圆心坐标
        // 第三个参数表示半径
        canvas.drawCircle(500, 500, 400, mPaint);//画一个容器,大的圆
    }

构造方法:

public RadialGradient(float x, float y, float radius, int[] colors, float[] positions,Shader.TileMode tile)
float x:  圆心X坐标
float y:  圆心Y坐标
float radius: 半径
int[] colors:  渲染颜色数组
floate[] positions: 相对位置数组,可为null,  若为null,可为null,颜色沿渐变线均匀分布
Shader.TileMode tile:渲染器平铺模式


public RadialGradient(float x, float y, float radius, int color0, int color1,Shader.TileMode tile)
float x:  圆心X坐标
float y:  圆心Y坐标
float radius: 半径
int color0: 圆心颜色
int color1: 圆边缘颜色
Shader.TileMode tile:渲染器平铺模式

4)SweepGradient——–扫描渲染

效果:

https://img-blog.csdnimg.cn/20190306164250730.png

代码:

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //1.中心X坐标 2.中心Y坐标 3.半径 4.颜色数组 5.相对位置数组,可为null 6.渲染器平铺模式
        SweepGradient mRadialGradient = new SweepGradient(240, 360, new int[]
                {Color.CYAN,Color.DKGRAY,Color.GRAY,Color.LTGRAY,Color.MAGENTA,
                Color.GREEN,Color.TRANSPARENT, Color.BLUE }, null);
        Paint mPaint = new Paint();
        mPaint.setShader(mRadialGradient);
        canvas.drawCircle(240, 360, 100, mPaint);
    }

5)ComposeShader——组合渲染

用法参考:https://blog.csdn.net/IO_Field/article/details/78460519

omposeShader的作用是实现两个颜色渐变效果的叠加,如BitmapShader与LinearGradient的混合渲染效果等,叠加的效果由过渡模式(Xfermode)或者PorterDuff.Mode来决定。

它有两个构造函数:

  • ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode)
  • ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)

参数解释:

  • shaderA:渲染效果
  • shaderB:渲染效果
  • mode:叠加的效果模式。对于过渡模式(Xfermode)或者PorterDuff.Mode

模式参考:https://blog.csdn.net/io_field/article/details/78222527

3.PathEffect

1)简介

含义就是用各种笔触去绘制路径。

分类有:

1.CornerPathEffect:用平滑的方式衔接Path的各部分

2.DashPathEffect :将Path的线段虚线化

3.PathDashPathEffect:与DashPathEffect效果类似但需要自定义路径虚线的样式

4.DiscretePathEffect:离散路径效果

5.ComposePathEffect :两种样式的组合。先使用第一种效果然后在此基础上应用第二种效果

6.SumPathEffect: 两种样式的叠加。先将两种路径效果叠加起来再作用于Path

2)示例

效果:

https://img-blog.csdnimg.cn/20190306170459320.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

代码:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画笔
        Paint mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.GREEN);
        mPaint.setStrokeWidth(8);
        //平滑
        Path path = new Path();
        path.moveTo(10, 100);
        for (int i = 1; i <= 30; i++) {
            path.lineTo(30 * i,(float)(Math.random()*100+100));
        }
        mPaint.setPathEffect(new CornerPathEffect(30));//拐角圆角的度数
        canvas.drawPath(path,mPaint);
        //虚线
        canvas.translate(0,300);
        //参数
        //1.数组float[ ] { }中第一个数表示每条实线的长度,第二个数表示每条虚线的长度
        //2.构造方法的第二个参数:phase表示偏移量,动态改变该值会使路径产生动画效果
        mPaint.setPathEffect(new DashPathEffect(new float[]{10,10},2));
        canvas.drawPath(path,mPaint);
    }

 

 

 

发布了32 篇原创文章 · 获赞 25 · 访问量 3万+
展开阅读全文

为什么TextView.onDraw会被调用???

09-02

[code="xml"] <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="----" /> <com.myTextViewDemo.MyTextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="change" /> </LinearLayout> [/code] [code="java"] public class MyTextViewDemo extends Activity { private MyTextView mt; private Button btn; private TextView tv; private int i = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mt = (MyTextView) findViewById(R.id.text); tv = (TextView) findViewById(R.id.title); btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { tv.setText("adsf:" + i++); } }); } } [/code] 自定义TextView [code="java"] public class MyTextView extends TextView { public MyTextView(Context context) { super(context); } public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); } public MyTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { System.out.println("--------------- onDraw --------------"); super.onDraw(canvas); } } [/code] 现在的问题是,当点击button时,会改变title的值,但是MyTextView.onDraw也会被调用,而且点击几次就调用几次,这是为什么?? 问答

请问我如何把edittext的文字通过onDraw放在画板上

05-04

我想做一个画板,现在想实现插入文字功能,目前点击屏幕时能弹出popupwindow,然后可以编辑EditText,请问如果在点击其他地方的时候让文字留在画板上 这是showTextPopup方法部分 ``` public void showTextPopup(float preX,float preY){ int x = (int) preX; int y = (int) preY; dp = new DrawPath(); dp.mOffX = preX; dp.mOffY = preY; dp.paint = mpaint; EditText mEditText = new EditText(getContext()); mEditText.setText("输入文字"); PopupWindow mTextPopup = new PopupWindow(mEditText, WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,true); mEditText.setFocusable(true); mEditText.setFocusableInTouchMode(true); //让popup显示在软键盘上面 mTextPopup.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); mEditText.requestFocus(); mTextPopup.setOutsideTouchable(true); mTextPopup.setBackgroundDrawable(new BitmapDrawable()); //自动弹出软键盘,会导致布局变化,重测量、绘制 InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Service.INPUT_METHOD_SERVICE); imm.toggleSoftInput(0,InputMethodManager.HIDE_NOT_ALWAYS); mTextPopup.showAtLocation(this, Gravity.TOP | Gravity.LEFT, x, y); invalidate(); } ``` 这是DrawPath类 ``` static class DrawPath{ public Path path;//路径 public Paint paint;//画笔 public Editable mText;//文本 //public int mWidth;//宽度 public float mOffX;//X轴偏移 public float mOffY;//Y轴偏移 } ``` 点击事件 ``` public boolean onTouchEvent(MotionEvent event){ //获取拖动事件的发生位置 float x = event.getX(); float y = event.getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: //从前一个点绘制到当前点之后,把当前点定义成下次绘制的一个点 if(currentStyle==3){ showTextPopup(x,y); } mpath = new Path(); //每一次记录的路径对象是不一样的 dp = new DrawPath(); dp.path = mpath; dp.paint = mpaint; mpath.moveTo(x,y); preX = x; preY = y; invalidate(); break; case MotionEvent.ACTION_MOVE: mpath.quadTo(preX,preY,x,y); preX = x; preY = y; break; case MotionEvent.ACTION_UP: mpath.lineTo(preX,preY); cachecanvas.drawPath(mpath,mpaint); //将一条完整的路径保存下来 savePath.add(dp); mpath = null;//重新置空 break; } invalidate(); //返回true表明处理方法已经处理该事件 return true; } ``` onDraw方法 ``` public void onDraw(Canvas canvas){ //Paint bmpPaint = new Paint(); //将cacheBitmap绘制到该View组件上 canvas.drawBitmap(cacheBitmap,0,0,mBitmapPaint);//显示旧的画布 //沿着path绘制 if(mpath != null) { canvas.drawPath(mpath, mpaint); } } ``` 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览