自定义控件玩套路以及canvas StaticLayout的使用

2023-11-13

遇到自定义控件的时候很苦恼、不知道从哪里下手、鄙人也是新手、记录下开发的思路
我们有时候需要把某一个功能封装成控件、很简单、写好布局、将其inflate出来
必要的属性、就跟普通的activity一样定义即可、context直接调用getContext();

public class DanmakuChannel extends RelativeLayout {

    public boolean isRunning = false;
    public DanmakuEntity mEntity;
    private DanmakuActionInter danAction;

    public DanmakuActionInter getDanAction() {
        return danAction;
    }

    public void setDanAction(DanmakuActionInter danAction) {
        this.danAction = danAction;
    }

    public DanmakuChannel(Context context) {
        super(context);
        init();
    }


    public DanmakuChannel(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DanmakuChannel(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public DanmakuChannel(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        LayoutInflater inflater = LayoutInflater.from(getContext());
        inflater.inflate(R.layout.danmaku_channel_layout, null);
    }

}

定义完了、在布局中调用即可

<com.just.sun.widget.danmu.DanmuBase.DanmakuChannel
            android:id="@+id/danA"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginTop="10dp" />

要处理点击事件、很简单、可以findViewById setOnclickListener、跟Activity是一样的、
如果更麻烦一点要捕获触摸事件、需要重写方法
下面我通过点击做了个小动画、点击屏幕会出现晃动的小手、然后消失

    public View.OnTouchListener onLightTouchListener = new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (model.liveEntity != null) {
                float x = event.getX();
                float y = event.getY();
                final int action = MotionEventCompat.getActionMasked(event);
                switch (action) {
                    case MotionEvent.ACTION_DOWN://单点触摸动作
                        break;
                    case MotionEvent.ACTION_UP://单点触摸离开动作

                        ImageView imageView = new ImageView(binding.getRoot().getContext());
                        imageView.setImageResource(R.drawable.light_touch);
                        final int width = imageView.getWidth();
                        final int height = imageView.getHeight();
                        //如果在边缘就不绘制
                        if (binding.getRoot().getWidth() - x > 130
                                && binding.getRoot().getHeight() - y > 130) {
                            sengLight();
                            RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                            imageView.setLayoutParams(param);
                            param.setMargins((int) x - 130 / 2, (int) y - 130 / 2, 0, 0);
                            binding.zanContainer.addView(imageView);
                            startAnim(x, y, imageView);
                        }
                        break;
                    case MotionEvent.ACTION_MOVE://触摸点移动动作
                        break;
                    case MotionEvent.ACTION_CANCEL://触摸动作取消
                        break;
                    case MotionEvent.ACTION_POINTER_DOWN://多点触摸动作
                        break;
                    case MotionEvent.ACTION_POINTER_UP://多点离开动作
                        break;
                }
                return true;
            }
            return true;
        }
    };

通过上面的case大家看到了、我获取控件的高宽是通过 getWidth()
但是有时候、获取到是0、是因为控件还没有绘制完成、那么我们可以

view.measure(-1, -1);
int measuredWidth = view.getMeasuredWidth();

如果我们自定义控件、需要canvas画的时候、获取到文字或者是bitmap的高宽很重要、
因为通过自定义坐标来定义画的起始位置、默认位置是 0,0 也就是左上角

画文字 我么常用到StaticLayout、下面讲一下StaticLayout
TextView就是用StaticLayout画的
他有三个构造函数

public StaticLayout(CharSequence source,
                    TextPaint paint,
                    int width,
                    Layout.Alignment align,
                    float spacingmult,
                    float spacingadd,
                    boolean includepad)

public StaticLayout(CharSequence source,
                    int bufstart,
                    int bufend,
                    TextPaint paint,
                    int outerwidth,
                    Layout.Alignment align,
                    float spacingmult,
                    float spacingadd,
                    boolean includepad)

public StaticLayout(CharSequence source,
                    int bufstart,
                    int bufend,
                    TextPaint paint,
                    int outerwidth,
                    Layout.Alignment align,
                    float spacingmult,
                    float spacingadd,
                    boolean includepad,
                    TextUtils.TruncateAt ellipsize,
                    int ellipsizedWidth)

最后一个构造参数讲解一下

1.需要分行的字符串

2.需要分行的字符串从第几的位置开始

3.需要分行的字符串到哪里结束

4.画笔对象

5.layout的宽度,字符串超出宽度时自动换行。

6.layout的对其方式,有ALIGN_CENTER, ALIGN_NORMAL, ALIGN_OPPOSITE 三种。

7.相对行间距,相对字体大小,1.5f表示行间距为1.5倍的字体高度。

8.在基础行距上添加多少

实际行间距等于这两者的和。

9.参数未知

10.从什么位置开始省略

11.超过多少开始省略
通常是这么用的

StaticLayout staticLayout = new StaticLayout(text, paint, (int) Math.ceil(StaticLayout.getDesiredWidth(text, paint)), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
                width = staticLayout.getWidth();
                height = staticLayout.getHeight();

getDesiredWidth(text, paint) 是Layout的方法、取得字符串显示的宽度。

也可以这样获取宽度

TextPaint paint = new TextPaint();
        paint.setTextSize(textSize);
        float contentLength = paint.measureText(content, 0, content.length());
        return contentLength;
        //这个方法 如果使用了ImageSpan会失效、建议用上一种方法

下面搞一下 canvas、站在巨人的肩膀上

一个画图需要四大基本要素:
1、一个用来保存像素的Bitmap;
2、一个Canvas画布,绘制Bitmap操作;
3、绘制的东西
4、绘制的画笔Paint(颜色和样式)

1、如何获得一个Canvas对象。

Canvas对象的获取方式有三种:

第一种我们通过重写View.onDraw方法,View中的Canvas对象会被当做参数传递过来,我们操作这个Canvas,效果会直接反应在View中。

第二种就是当你想自己创建一个Canvas对象。从上面的基本要素可以明白,一个Canvas对象一定是结合了一个Bitmap对象的。所以一定要为一个Canvas对象设置一个Bitmap对象。

 //得到一个Bitmap对象,当然也可以使用别的方式得到。但是要注意,改bitmap一定要是mutable(异变的)  
        Bitmap b = Bitmap.createBitmap(100,100, Bitmap.Config.ARGB_8888);  
        Canvas c = new Canvas(b);  
        /**先new一个Canvas对象,在调用setBitmap方法,一样的效果 
         * Canvas c = new Canvas(); 
         * c.setBitmap(b); 
         */ 

第三种方式,是调用SurfaceHolder.lockCanvas(),返回一个Canvas对象。
2、canvas可以绘制的内容

1)填充

  drawARGB(int a, int r, int g, int b)
  drawColor(int color)
  drawRGB(int r, int g, int b)
  drawColor(int color, PorterDuff.Mode mode)

2)几何图形

canvas.drawArc (扇形)

canvas.drawCircle(圆)

 canvas.drawOval(椭圆)

 canvas.drawLine(线)

 canvas.drawPoint(点)

 canvas.drawRect(矩形)

 canvas.drawRoundRect(圆角矩形)

 canvas.drawVertices(顶点)

 cnavas.drawPath(路径)

3)图片

   canvas.drawBitmap (位图)

   canvas.drawPicture (图片)

4)文本

   canvas.drawText

3. Canvas的保存和回滚

为了方便一些转换操作,Canvas还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置。

Canvas提供的该功能的API如下:


    /** 
         * 保存当前的matrix和clip到私有的栈中(Skia内部实现)。任何matrix变换和clip操作都会在调用restore的时候还原。 
         * @return 返回值可以传入到restoreToCount()方法,以返回到某个save状态之前。 
         */  
        public native int save();  



        /** 
         * 传入一个标志,来表示当restore 的时候,哪些参数需要还原。该参数定义在Canvas中,参照下面。 
         * save()方法默认的是还原matrix和clip,但是可以使用这个方法指定哪些需要还原。并且只有指定matrix和clip才有效,其余的几个参数是 
         * 用于saveLayer()和saveLayerAlpha()方法 的。 
         */  
        public native int save(int saveFlags);  


        /** 
         * 回到上一个save调用之前的状态,如果restore调用的次数大于save方法,会出错。 
         */  
        public native void restore();  

         /** 
         * 返回栈中保存的状态,值等译 save()调用次数-restore()调用次数 
         */  
        public native int getSaveCount();  




        /** 
         * 回到任何一个save()方法调用之前的状态 
         */  
        public native void restoreToCount(int saveCount);  



    /**saveFlags的参数*/  
     public static final int MATRIX_SAVE_FLAG = 0x01;//需要还原Matrix  
        public static final int CLIP_SAVE_FLAG = 0x02;//需要还原Clip  
    /**下面三个参数在saveLayer的时候使用,具体作用,没有搞明白*/  
       public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;  
      public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;  
      public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;  
        public static final int ALL_SAVE_FLAG = 0x1F; //还原所有  

    /*关于saveLayer的具体flags还不大明白它的含义,具体怎么使用在下面例子中*/  
     public int saveLayer(RectF bounds, Paint paint, int saveFlags)  
    public int saveLayer(float left, float top, float right, float bottom,  
                             Paint paint, int saveFlags)   
     public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)  
    public int saveLayerAlpha(float left, float top, float right, float bottom,  
                                  int alpha, int saveFlags)  

这里写图片描述

saveLayer

Canvas 在一般的情况下可以看作是一张画布,所有的绘图操作如drawBitmap, drawCircle都发生在这张画布上,这张画板还定义了一些属性比如Matrix,颜色等等。但是如果需要实现一些相对复杂的绘图操作,比如多层动画,地图(地图可以有多个地图层叠加而成,比如:政区层,道路层,兴趣点层)。Canvas提供了图层(Layer)支持,缺省情况可以看作是只有一个图层Layer。如果需要按层次来绘图,Android的Canvas可以使用SaveLayerXXX, Restore 来创建一些中间层,对于这些Layer是按照“栈结构“来管理的:
这里写图片描述

创建一个新的Layer到“栈”中,可以使用saveLayer, savaLayerAlpha, 从“栈”中推出一个Layer,可以使用restore,restoreToCount。但Layer入栈时,后续的DrawXXX操作都发生在这个Layer上,而Layer退栈时,就会把本层绘制的图像“绘制”到上层或是Canvas上,在复制Layer到Canvas上时,可以指定Layer的透明度(Layer),这是在创建Layer时指定的:public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)本例Layers 介绍了图层的基本用法:Canvas可以看做是由两个图层(Layer)构成的,为了更好的说明问题,我们将代码稍微修改一下,缺省图层绘制一个红色的圆,在新的图层画一个蓝色的圆,新图层的透明度为0×88。

 public class Layers extends Activity {  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(new SampleView(this));  
    }  

    private static class SampleView extends View {  
        private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG  
                | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG  
                | Canvas.CLIP_TO_LAYER_SAVE_FLAG;  

        private Paint mPaint;  

        public SampleView(Context context) {  
            super(context);  
            setFocusable(true);  

            mPaint = new Paint();  
            mPaint.setAntiAlias(true);  
        }  

        @Override  
        protected void onDraw(Canvas canvas) {  
            canvas.drawColor(Color.WHITE);    
            canvas.translate(10, 10);    
            mPaint.setColor(Color.RED);    
            canvas.drawCircle(75, 75, 75, mPaint);    
            canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, LAYER_FLAGS);    
            mPaint.setColor(Color.BLUE);    
            canvas.drawCircle(125, 125, 75, mPaint);    
            canvas.restore();   
         }  
    }  
} 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义控件玩套路以及canvas StaticLayout的使用 的相关文章

  • 检测画布内的鼠标单击位置

    我在尝试定义一个单击空白区域的函数时遇到了一个真正的问题 到目前为止 我已经成功地定义了单击一个对象的位置 其中有 10 个 但现在我需要一个单独的函数 以便在不单击任何对象时使用 总体思路可以在以下位置找到 http deciballs
  • 在画布中将 Raphael JS 生成的 SVG 保存为 png 时出现问题

    我正在尝试转换由以下方式生成的 SVG拉斐尔 JS http raphaeljs com 以及用户 因为您可以拖动和旋转图像 我跟着这个在浏览器中将 SVG 转换为图像 JPEG PNG 等 https stackoverflow com
  • toDataURL 不是函数

    我正在尝试为画布生成一个网址 以下是我遵循的步骤 var can document getElementsByTagName canvas var src can toDataURL image png 当我尝试在 firebug 上运行上
  • HTML5 Canvas 动画偶尔出现抖动/犹豫/卡顿

    在 Firefox 11 中 我在使用 HTML5 画布和翻译的一些基本动画中偶尔遇到抖动 犹豫 口吃的情况 请看下面的例子 http jsfiddle net ACRdx http jsfiddle net ACRdx 上面示例中的配置似
  • 如何制作带有圆角的 tkinter 画布矩形?

    我想创建一个带圆角的矩形 我正在使用 tkinter 的画布 为托比亚斯的方法提供另一种方法确实是用一个多边形来实现 如果您担心优化 或者不必担心引用单个对象的标签系统 那么这将具有成为一个画布对象的优点 该代码有点长 但非常基本 因为它只
  • 使用drawImage()在画布上输出固定大小的图像?

    我该如何使用drawImage 在a上输出全尺寸图像300px X 380px画布无论源图像大小如何 例子 1 如果有一个图像75px X 95px我希望能够将其绘制以适合300px X 380px帆布 2 如果有一个图像1500px X
  • 保持文本在画布上垂直居中

    我遇到的问题是将用户输入的文本保持在画布元素内垂直居中 我已经构建了一个测试环境来尝试解决这个问题 我在这篇文章中提供了该环境以及小提琴 这是我的代码 HTML Enter Your Text br
  • HTML5画布中绘制图像对象的限制区域

    我想限制画布上可以绘制图像的区域 我正在使用 Fabric js 我尝试了以下链接 但它对我不起作用 在 Fabric js 中设置对象拖动限制 https stackoverflow com questions 19979644 set
  • 画布已被跨源数据本地图像污染

    这个问题已经被问了很多次 但我只是不明白为什么这种情况会发生在我身上 基本上 我有一个画布和一个图像 当我尝试这样做时 var canvas document getElementById somecanvas var ctx canvas
  • 将内部图像替换为外部图像

    用户单击 蒙版 并上传图像 其显示的同一张图片两次 also Edit文本正在图像上显示 一旦用户单击 编辑文本 我们就会显示pop up box 在那里我们可以看到Zoomin Zoomout按钮正在显示 Issue 一旦我们点击这些按钮
  • 是否可以在浏览器中使用 javascript 对用户系统进行基准测试

    随着 Html5 开始普及 我们看到更多关于视频或画布元素等的实验 当使用画布进行实验时 例如用粒子制作烟花 1000 个粒子可能在现代机器上运行良好 但在 3 年机器上可能会运行得很慢 无论如何 是否可以对用户系统进行基准测试以动态更改画
  • 当我使用 ctx.drawImage() 在画布中放置另一个图像时,无法将画布另存为图像

    我正在尝试制作绘图应用程序 您可以在画布上绘制一些内容 并通过单击 保存 按钮将结果保存为服务器上的图像 您还可以放置另一张图像作为绘图的背景 问题是 当我使用 ctx drawImage 将图像放入画布时 我无法将画布保存为图像 因为什么
  • Canvas 动画在 FireFox 中卡顿,但在 Chrome 中完美

    我最近开始做一些 HTML5 Canvas 的东西 并且很高兴地开展我的业务 在 Chrome 中测试东西 直到我决定尝试我在 Firefox 中所做的事情 效果不太好 这是我正在做的事情的一个简单的例子 设置基本的 requestAnim
  • 为什么 Chart.js 画布不考虑容器元素的填充?

    我将 Chart js 与简单的折线图一起使用 但 Chart js 计算的宽度和高度属性似乎基于父元素的总宽度和高度 忽略填充 var options maintainAspectRatio false responsive true v
  • 如何检测形状是否被单击(HTML5 画布)?

    我正在使用画布绘制不同的形状 如矩形 三角形 六边形等lineTo方法如这个博客 http blog riacode in 2011 03 03 drawing regular polygons in html5 canvas 我只是想要一
  • HTML5 - 创建画布视口

    我有一个 2D 数组 宽 30 下 20 然而 视口仅绘制横向 15 和向下 10 的内容 我最初有一个这样的游戏 我一直在努力实现这样的目标 这是我的小提琴 http jsfiddle net sTr7q http jsfiddle ne
  • html画布绘图显示出来

    我确信这个问题在我还找不到答案之前就已经被问过 我想通过在顶部绘制另一个白色矩形来擦除黑色矩形的一部分 但是许多原始黑色矩形显示出来 就像正在平均一样 canvas document getElementById canvas contex
  • 在 SVG 中绘制 DOM 对象时如何在 Canvas 中使用 Google 字体?

    根据 Mozilla 的文档 您可以在 Canvas 上绘制复杂的 HTML 例如this https developer mozilla org en US docs Web API Canvas API Drawing DOM obje
  • 从 url 加载图像并绘制到 HTML5 Canvas

    我在从 javascript 中的 url 加载图像时遇到问题 下面的代码可以工作 但我不想从 html 加载图像 我想使用纯 JavaScript 从 url 加载图像 var c document getElementById myCa
  • KineticJS - 将舞台缩放到视口

    我正在努力将默认分辨率设置为 1366x756 我会根据视口来放大和缩小它 类似于此处显示的示例 http blogs msdn com b davrous archive 2012 04 06 modernizing your html5

随机推荐

  • STM32串口中断处理中.是否需要清除接受/发送完成/中断 标志位的问题.

    关于是否在串口中断服务程序中 是否加清除标志位操作 手册有说明 正常的读写DR寄存器都能达到清楚标志的效果 所以除了多缓存通信的情况下 没必要增加清除标志位 两个清除函数 USART ClearFlag 清除完成标志位 USART Clea
  • ShardingSphere-JDBC 5.0.0-beta使用:数据源拒绝建立连接,来自服务器的消息:“连接太多”

    问题分析 I wonder if the jar package is missing This is a non Maven project 问题处理 调试发现 问题出在少了蛮多依赖包 由于是非maven项目 有些jar包还可能冲突 版本
  • Java Robot 编写脚本机器人(一)基本用法测试

    Test public void test throws AWTException 获取机器人类 Robot robot new Robot 获取当前屏幕 Point point MouseInfo getPointerInfo getLo
  • 【Python_PySide2学习笔记(一)】PySide2动态加载UI方式,重写关闭窗体事件

    PySide2设置关闭提示窗口 动态加载UI方式 重写关闭窗体事件 前言 转载 https blog csdn net qq 44703282 article details 119830807 在此链接中介绍了两种重写关闭提示窗体事件的方
  • Vue CLI3配置详解-----脚手架的认识以及项目初始化、项目目录结构

    使用Vue CLI3创建项目 脚手架 scaffold 指施工现场为工人操作并解决垂直和水平运输而搭设的各种支架 建筑界的通用术语 写在前面 如果你只是简单的写几个Vue的 Demo 程序 那你不需要Vue CLI 如果你 开发大型项目 那
  • React中函数组件与类组件的区别

    React中函数组件与类组件的区别 一 组件定义 函数组件 import React from react function Index props const value setvalue useState React return di
  • C语言的可变参数函数理解与应用

    一 可变参数函数的理解 官方定义 C语言允许定义参数数量为可变的函数 这称为可变参数函数 它与传统意义上的强制定义固定参数的函数不同 可变参数函数应用最广的是格式化输入输出函数 如printf scanf 可支持任意参数输入输出 可变参数函
  • 【OpenCV C++】光流法进行运动目标检测

    OpenCV C 光流法进行运动目标检测 什么是光流 程序说明 代码 运行效果 什么是光流 光流 optical flow 是空间运动物体在观察成像平面上的像素运动的瞬时速度 光流法是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性
  • c/c++时间类型

    1 time t time t 类型 这本质上是一个长整数 表示从1970 01 01 00 00 00到目前计时时间的秒数 如果需要更精确一点的 可以使用timeval精确到毫秒 time t cur time NULL 2 struct
  • 刷题day_11:两个数组的交集

    题意描述 给定两个数组 编写一个函数来计算它们的交集 有两种方法 1 利用unordered set容器编写 2 和上一题一样利用数组来编写 利用unordered set容器的C 代码如下 class Solution public ve
  • solr搜索引擎 copyField字段 检索查询

    添加一个文档 查询添加的文档 以上详细介绍了query里面的参数详解 当不输入任何条件时 进行查询 看看返回结果 返回了刚才添加进去的文档 添加文档时 我们添加了id title content 分词 那么如果我们想自己定义 该如何 id
  • 彩票系统的Java实现

    能够实现的功能有六个 1 充值 2 查看账户资金 3 开始购买彩票 4 开奖 5 查看当前购买的彩票 6 退出系统 import java util Arrays import java util Random import java ut
  • Docker使用Link在容器之间建立连接

    在使用Docker的时候我们会常常碰到这么一种应用 就是我需要两个或多个容器 其中某些容器需要使用另外一些容器提供的服务 比如这么一种情况 我们需要一个容器来提供mysql的数据库服务 而另外两个容器作为客户端来连接使用mysql数据库服务
  • arm64 ubuntu18.04桌面文件系统制作

    适用于RK3568 亲测有效 1 下载ARM64根文件系统 ubuntu base 18 04 5 base arm64 tar gz http cdimage ubuntu com ubuntu base releases 18 04 r
  • timing 分析基本概念-min period

    min period 一般对memory 进行最小周期的检查 如有一个memory 最高频率是1GHz 但是我们想让它工作到2GHz 那么就会出现min period 的violation 在library 中可以查到timing type
  • 【模板】归并排序

    题目链接 https www luogu com cn problem P1177 1945年由约翰 冯 诺伊曼 John von Neumann 首次提出 如上图所示 归并排序的执行流程为 不断地将当前序列平均分割成 2 个子序列 直到不
  • qt:构建失败,输出Error while building/deploying project SoftwareForAUV (kit: Desktop Qt 5.15.2 MinGW 64-bit

    打开qt项目的时候报错 我能想到就两个原因 1 路径中含有中文名 常见的就是项目拖到桌面 直接打开pro文件 如果 路径中有中文名 就会报错 2 编译器选择了select all 在打开项目选择编译器的界面 选择了安装的多个编译器 解决办法
  • Java连接超时

    java net SocketTimeoutException connect timed out 通常表示无法建立到远程服务器的连接 可能是由于网络问题或目标服务器不可用导致的 这种情况下 可以尝试以下几种解决方法 检查网络连接 可以检查
  • Express基本使用(Node.js)(1)

    Express基本使用 Node js Express是基于node js内置http模块二次开发的中间件 可以提高程序员的开发效率 01 使用express发送get和post请求 导入express模块 const express re
  • 自定义控件玩套路以及canvas StaticLayout的使用

    遇到自定义控件的时候很苦恼 不知道从哪里下手 鄙人也是新手 记录下开发的思路 我们有时候需要把某一个功能封装成控件 很简单 写好布局 将其inflate出来 必要的属性 就跟普通的activity一样定义即可 context直接调用getC