前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 自定义View

Android 自定义View

作者头像
艳龙
发布2022-05-13 17:57:23
4520
发布2022-05-13 17:57:23
举报
文章被收录于专栏:yanlongli_艳龙

这篇文章是一个自定义View的学习总结文章,会介绍自定义view的整体流程和部分相关的api使用,并不会对所有使用到的api进行介绍,所以阅读的话需要有一些Android的开发基础。

Google为Android开发者提供了非常多的控件,常用的有Button/TextView/ImageView/EditText 等, 日常的开发中大部分场景都可以使用这些基础控件完成UI相关的需求。 可是在很多时候设计师都会拿着ios的手机,来让你实现ios上一样的效果 😫,这是以前比较头疼的一个问题,深入了解自定义View后,感觉以后应该不会再有这样的困扰了。

参考文章: HenCoder Canvas Paint

系统绘制View的顺序

先看看系统提供的组件是怎么绘制出来的, 下面的这段源码是系统绘制View的部分关键代码:

代码语言:javascript
复制
public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {

     /**
      * 去掉无关代码
      */

     /**
     * Manually render this view (and all of its children) to the given Canvas.
     * The view must have already done a full layout before this function is
     * called.  When implementing a view, implement
     * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.
     * If you do need to override this method, call the superclass version.
     *
     * @param canvas The Canvas to which the View is rendered.
     */
    @CallSuper
    public void draw(Canvas canvas) {
         //draw 方法负责调度绘制顺序,先画什么再画什么等
         /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */
        //....
        // 常用到的覆盖方法有如下几个,顺序如果
       drawBackground(canvas);
       onDraw(canvas);
       dispatchDraw(canvas);
       onDrawForeground(canvas);

       //....
    }
}

draw() 负责调度绘制顺序,通过复写不同方法实现不同的覆盖效果

  1. drawBackground() 绘制背景 (需要注意的是drawBackground()不能重写)
  2. onDraw() 绘制view的主体部分
  3. dispatchDraw()绘制view的子类
  4. onDrawForeground()绘制view的前景

他们的层级关系是这样的:

事件分发(Draw).png

大部分情况下,复写onDraw() 方法就可以满足我们的需求了,当然一些特殊的情况下,也可以根据具体的需求来决定复写哪个函数

自定义View

  • 如何自定义一个View
  1. 自定义View 可以 extends View, 或者扩展系统已有的View,例如 extends TextView
  2. 重写 onDraw 方法(或者dispatchDraw/onDrawForeground
代码语言:javascript
复制
/**
 * 一个自定义的View
 */
public class CustomView extends View {

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

         // 简单的显示一行文字打印
        canvas.drawText("Hello CustomView", 50, 100, paint);
    }
}
  • 自定义View常用api(只列举个别用法,更多用法可以参考官网 CanvasPaint或者HenCoder
  1. View的绘制是通过使用 CanvasPaint 来完成,

其中Canvas.drawXXX() 是自定义绘制最基本的操作 -Canvas.drawColor(@ColorInt int color) 设置绘制的背景色

代码语言:javascript
复制
drawColor(Color.BLACK);  // 纯黑

图片来源HenCoder

-canvas.drawText() 绘制文字

代码语言:javascript
复制
text = "Hello Word!";
paint.setTextSize(60);
paint.setColor(Color.RED);
canvas.drawText(text, 50, 100, paint);

可以通过setTextSkewX(倾斜)/setUnderlineText(下划线)/setStrikeThruText(删除线)等相关方法来设置文字的不同显示

-canvas.drawCircle() 文字几何图形

代码语言:javascript
复制
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(0);
canvas.drawCircle(300f,50f, 50f, mPaint);


mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(450f,50f, 50f, mPaint);

// FILL 为填充
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLUE);
canvas.drawCircle(300f,200f, 50f, mPaint);

// STROKE 为不填充,空心圆
mPaint.setStyle(Paint.Style.STROKE);
//设置颜色 。
mPaint.setColor(Color.BLACK);
//设置填充样式
mPaint.setStyle(Paint.Style.STROKE);
// 设置外框的大小
mPaint.setStrokeWidth(20);
canvas.drawCircle(450f,200f, 50f, mPaint);

绘制图片等和绘制几何图形类似,使用drawBitmap() 方法。

其中几何图形和图片等,可以进行移动/缩放/旋转 等变化, 具体等变化太多,这里就不一一列举,需要可以去查看上面的参考文章。

学会了 drawxxx() 的方法,就可以绘制如下的表格等就不是问题了:

代码语言:javascript
复制
     //  这只是 demo 代码,图和代码有部分差异
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int pointX = (int)(getWidth() * 0.11f);
        int pointY = (int)(getHeight() * 0.7f);

        mPaint.setAntiAlias(true);

        mPath.moveTo(pointX,20);
        mPath.lineTo(pointX, pointY);
        mPath.rLineTo((int)(getWidth() * 0.8f), 0);

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.WHITE);
        mPaint.setStrokeWidth(3);
        canvas.drawPath(mPath, mPaint);

        mPaint.setTextSize(42);
        canvas.drawText(NAME, getWidth() / 2 - 50, getHeight() - (int)(getHeight() * 0.15f), mPaint);

        mPaint.setTextSize(30);
        for (int i = 0; i < nameList.length; i++) {
            int x = pointX + ((i+1) * OFFSET_RECT) + i * RECT_WIDTH;
            if (i == 0) {
                x = pointX + OFFSET_RECT;
            }

            canvas.drawText(nameList[i], x, pointY + 30, mPaint);
        }

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.GREEN);
        for (int i = 0; i < nameList.length; i++) {
            int x = pointX + ((i+1) * OFFSET_RECT) + i * RECT_WIDTH;
            if (i == 0) {
                x = pointX + OFFSET_RECT;
            }

            int height = random.nextInt(300);

            canvas.drawRect(x,(pointY - height), x + RECT_WIDTH, pointY, mPaint);
        }
    }
代码语言:javascript
复制
   //  这只是 demo 代码,图和代码有部分差异
   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setTextSize(30);
        canvas.drawText("Lollipop", 100, 100, mPaint);
//        canvas.drawLine(100, 100, mPaint);

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.RED);
        canvas.drawArc(rectFFirst,180, 120, true, mPaint);


        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectFSecond,80, 100, true, mPaint);


        mPaint.setColor(Color.GREEN);
        canvas.drawArc(rectFSecond,40, 38, true, mPaint);

        mPaint.setColor(Color.GRAY);
        canvas.drawArc(rectFSecond,20, 18, true, mPaint);

        mPaint.setColor(Color.WHITE);
        canvas.drawArc(rectFSecond,0, 18, true, mPaint);


        mPaint.setColor(Color.YELLOW);
        canvas.drawArc(rectFSecond,-60, 60, true, mPaint);
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 系统绘制View的顺序
  • 自定义View
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档