自定义控件初学篇——onDraw()方法

许多APP上都会有一些比较酷炫美观的动画效果和自定义控件,所以最近研究了一下,又遇到一些疑惑和问题,所以这里记录一下。

自定义控件经常会要提到三个方法,也就是onLayout(),onMeasure()和onDraw()。今天我暂时先讲一下自己对onDraw()方法的学习。

首先我们自定义一个MyView1继承于View类,然后会自动提示我们添加一些方法,这些就不细说了。

在这些提示的方法里面有一个方法:

public MyView1(Context context, AttributeSet attrs, int defStyleAttr) {}
首先我在这个方法里面新建了一个TypeArray对象,通过它来获得MyView1的一些自定义属性。这里我们要新建一个xml格式的文件。
里面的代码如下:
<declare-styleable name="MyView1">
    <attr name="left_circle_radius" format="dimension" />
    <attr name="left_circle_color" format="color" />
    <attr name="top_circle_radius" format="dimension" />
    <attr name="top_circle_color" format="color" />
    <attr name="right_circle_radius" format="dimension" />
    <attr name="right_circle_color" format="color" />
    <attr name="bottom_circle_radius" format="dimension" />
    <attr name="bottom_circle_color" format="color" />
</declare-styleable>
其实也就是定义这个View中需要用到的一些属性,需要注意的是记得写上format的类型,至于为什么,后面我会讲到。在这个View里面我定义了四个圆的半径和颜色。
然后在代码里面我们要获得它们,这里要注意的是获得它们必须是“declare-styleable的name+ attr的name”,例如上面的“MyView1_left_circle_radius",这应该是他们固定的一种格式,不这么写的话会报错的。
除了获得这些属性外,我们还要实例化Paint类的对象。
mPaint = new Paint();
mPaint.setAlpha(180); // 透明度
mPaint.setStrokeWidth(2); // 画笔宽度
mPaint.setAntiAlias(true); // 消除锯齿
mPaint.setTextAlign(Paint.Align.CENTER); // 文字居中
上面是Paint类比较常用的几种方法,注释写的很仔细了,所以就不再赘述了。

接下来说onDraw()方法,看到这个方法,大家就知道它跟绘画有关。

onDraw()方法中有一个Canvas类,也就是画布的意思。Canvas类有许多绘画的方法,比如
画圆调用canvas的
drawCircle(left, top, radius, paint);
方法中的属性分别对应要绘制的这个圆最左侧的横坐标,最上侧的纵坐标,半径,和画笔。
画直线调用canvas的             
drawLine(left, top, right, bottom, paint)
方法中的属性也就是这条直线左上右下的四个坐标点,因为宽度已经被paint的setStrokeWidth()方法给固定了。
 画虚线稍微比他们复杂一些,要用到PathEffect类,下面有具体的注释。
PathEffect effects = new DashPathEffect(new float[]{1,2,4,8},1); // 绘制长度1的实线,再绘制长度2的空白,再绘制长度4的实线,再绘制长度8的空白

接下来附上本人写的demo的部分代码:

mPaint.setColor(Color.CYAN);
canvas.drawLine(getWidth() - getWidth() / 5 * 4 + 40, getHeight() / 2, getWidth() - getWidth() / 5 - 40, getHeight() / 2, mPaint); // 划线,左,上,右,下,画笔
mPaint.setColor(leftCircleColor);
/**
 * 1.Paint.Style.STROKE:描边
 * 2.Paint.Style.FILL_AND_STROKE:描边并填充
 * 3.Paint.Style.FILL:填充
 * 默认FILL
 */
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(getWidth() - getWidth() / 5 * 4, getHeight() / 2, leftCircleRadius, mPaint); // 画圆,左,上,半径,画笔
PathEffect effects = new DashPathEffect(new float[]{1,2,4,8},1); // 绘制长度1的实线,再绘制长度2的空白,再绘制长度4的实线,再绘制长度8的空白
mPaint.setPathEffect(effects);
mPaint.setColor(topCircleColor);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(getWidth() / 2, getHeight() - getHeight() / 5 * 4, topCircleRadius, mPaint);
canvas.drawCircle();
最后就是在Activity里面使用这个MyView1了,首先自然是像那些普通控件一样在activity_main.xml中定义,代码如下:

<com.xue.myview1.MyView1
    android:id="@+id/myview1_main"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xue:left_circle_color="#00FF00"
    xue:left_circle_radius="30dp"
    xue:top_circle_color="#303F9F"
    xue:top_circle_radius="30dp"
    xue:right_circle_color="#FF4081"
    xue:right_circle_radius="30dp"
    xue:bottom_circle_color="#FFFF00"
    xue:bottom_circle_radius="30dp"/>
,然后在Activity定义MyView1的对象并找到就好了。

然而,在开发完成的时候遇到了下面这个问题:

Error:Execution failed for task ':app:processDebugResources'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\adt-bundle-windows-x86_64-20140624\sdk\build-tools\23.0.1\aapt.exe'' finished with non-zero exit value 1
这个问题困扰了我几个小时,刚开始的时候以为是

xmlns:xue="http://schemas.android.com/apk/res-auto"这条语句的问题,可是把res-auto换成对应的包名还是没有用,也仔细查看过语句,可是由于报错的信息中没有定位到错误的地方。最后还是解决了,我发现是导致这个报错的原因如下:
1、xml文件中"xue:"后面定义的属性和attrs中的属性有出入;
2、"30dp"和”#000000"和属性的类型有出入,开始的时候没有写format="color"和format="dimension",而代码中定义的是

private int leftCircleColor = Color.WHITE;
private float leftCircleRadius = 40.0f;

leftCircleColor = a.getColor(attr, leftCircleColor);
leftCircleRadius = a.getDimension(attr, leftCircleRadius);

这就是我初次学习自定义View的一些小知识的理解和使用。

发布了51 篇原创文章 · 获赞 8 · 访问量 5万+
展开阅读全文

请问我如何把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官方博客

分享到微信朋友圈

×

扫一扫,手机浏览