自定义View开发笔记(ing)

作者: 凌川江雪 | 来源:发表于2019-09-14 12:36 被阅读0次

    最近拜读一本书——《Android自定义控件开发入门与实战》,感慨良多,实为佳作,这里做做笔记摘录,写写自己的心得,作巩固分享之用;

    画弧原理

    • 首先上Canvas下画弧函数源码:
        public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
            throw new RuntimeException("Stub!");
        }
    
        public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
            throw new RuntimeException("Stub!");
        }
    
    • 参数意义:
      oval :用于确定圆弧形状与尺寸的椭圆边界(即椭圆外切矩形)
      startAngle :开始角度(以时钟3点的方向为0°,逆时针为正方向
      sweepAngle : 扫过角度(以时钟3点的方向为0°,逆时针为正方向
      useCenter:是否有弧的两边,为true时带有两边,为false时不带,只有一条弧;
      paint:绘制圆弧的画笔

    • 绘制圆弧原理

    • RectF(float left, float top, float right, float bottom)得到一个矩形,
      此虚拟矩形内切绘制一个椭圆(如果长和宽相等,则为圆)。

    • 以矩形的中心为圆心,以时钟3点的方向为0°,
      由中心以0°径向画出一条射线,
      逆时针为正方向
      从0°正方向旋转startAngle度,
      射线和矩形内切椭圆相交得到一条直线段和一个交点。

    • 从这条直线开始,以顺时针为正方向,射线旋转sweepAngle度,
      矩形内切椭圆相交,得到另一条直线段和交点,
      这样一来,
      前后两个交点圆弧的两个端点
      射线在这两条交线之间扫过的扇面外弧,即所画圆弧

    相关阅读:

    单词普及

    • intersect.
      美 [ˌɪntərˈsekt]
      vt.横断,横切,横穿;
      vt.& vi.(指线条、道路等)相交,交叉;

    • cruncher.
      美 [k'rʌntʃər]
      [计]数字计算器;

    postInvalidate()、invalidate()之别

    • postInvalidate()和invalidate()都是用来重绘控件的,
      区别是invalidate()一定要在主线程中执行,否则就会报错;
      而postInvalidate()函数则没有那么多讲究,

      它可以在任何线程中执行,而不必一定是主线程,

    关于addView()、removeView()

    关于add、remove的速度
    • 下面代码案例中:
      SpiderView是一个自定义控件,
      ll_nextParent 是主布局下的一个LinearLayout,
      现在在这个LinearLayout下做组件增删操作;
    public class MainActivity extends AppCompatActivity {
    
        private LinearLayout ll_nextParent;
        private SpiderView spiderViewOri;
        private LinearLayout.LayoutParams layoutParams;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initViews();
            configCustomViews(0);
        }
    
        private void initViews() {
    
            ll_nextParent = findViewById(R.id.ll_nextParent);
    
            layoutParams = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT);
    
            ll_nextParent.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    //经过这个测试,这里的删除添加是毫秒级别的,
                    // 添加之后删除的速度人眼分辨不出
    
                    Toast.makeText(MainActivity.this, "shanchu", Toast.LENGTH_SHORT).show();
                    ll_nextParent.removeView(spiderViewOri);
    
    //                TextView test = new TextView(MainActivity.this);
    //                test.setText("sdadasdasdada");
    //                ll_nextParent.addView(test);
    
                    Toast.makeText(MainActivity.this, "tianjia", Toast.LENGTH_SHORT).show();
                    ll_nextParent.addView(spiderViewOri, layoutParams);
                }
            });
        }
    
    
        private void configCustomViews(int drawId) {
            switch (drawId) {
                case 0:
                    spiderViewOri = new SpiderView(this);
                    ll_nextParent.addView(spiderViewOri, layoutParams);
                    break;
    
                case 1:
                    break;
    
                default:
            }
        }
    
    }
    
    
    • 运行的时候,
      我们点击触发回调,先删后加(先removeView后addView),
      而这个过程中呢,
      更新布局的速度是毫秒级的,
      人眼无法分辨;
      后续在做根布局增删组件的时候,可以利用这个点;

    关于报错

    Bug.1

    场景:主布局中,
    LinearLayout1下套ScrollView,
    ScrollView下套LinearLayout2,
    LinearLayout2中添加复杂的自定义View,
    比如SpiderView

    此时如果不做任何处理的话,
    运行时一般那个复杂的自定义View是 不会被渲染出来的,
    并且会报下面这个错:
    Skipped xxx frames! The application may be doing too much work on its main thread
    跳帧过多,程序在主线程中做了太多事情了,需要优化逻辑

    关于自定义控件的宽高

    所有的自定义控件在被引入布局时,
    layout_width和layout_height属性的值默认都是match_parent,
    当然可以通过测量控件大小以使用wrap_content

    自定义组件引入

    有xml引入和动态添加两种方法;

    如何通过文件名拿到对应的资源ID


    getIdentifier()函数的完整声明如下:

    • int getIdentifier(String name,String defType,String defPackage)

    • String name:所要查找资源ID的资源名称。

    • String defType:资源所在的文件类型。

    • String defPackage:应用包名。
      由于我们的图片资源在drawable系列文件夹中,所以defType就是“drawable”。

    • 如果想获得string,则可以这样写:
      getResources().getIdentifier("name","string",packdgeName);

    • 如果想获得array中的数组,则可以这样写:
      getResources().getIdentifier("name","array",packdgeName);










    相关文章

      网友评论

        本文标题:自定义View开发笔记(ing)

        本文链接:https://www.haomeiwen.com/subject/uxcilctx.html