美文网首页Android控件
Android自定义控件零基础简述「JAVA,基础」

Android自定义控件零基础简述「JAVA,基础」

作者: 唐_夏影 | 来源:发表于2018-09-01 22:48 被阅读50次

    Android自定义控件「JAVA,基础」

    我们有原生控件可以使用,但特定需求下,仍然无法满足我们,这时我们只能去自定义控件。

    自定义后如果开源,就成了我们熟悉的开源库,轮子。例如以下两个开源库,选项卡开源库FlycoTabLayout,动画开源库lottie-android

    源代码已上传至View文件夹

    Canvas操作

    创建/module/canvasx/XView类,让该类继承于View类。使用快捷键Alt+insert,选择第一个Construct重写该类的必须要的两个构造方法。

    • 如不重写构造一程序在编译时就会报红
    • 如不重写构造二程序在编译时不会报红,但是当运行起来后,程序会崩溃,出现android.view.InflateException: Binary XML file line #9: 异常

    关于这两个构造方法何时会被调用稍后会给出解释

    import android.content.Context;
    import android.view.View;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    public class XView extends View{
        public XView(Context context) {
            super(context);
        }
        
        public XView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    }
    

    View类是所有控件的父类,例如我们熟悉的TextView,ImageView,而TextView又是EditView,button的父类

    继承关系

    子类可使用父类的非私有方法,而父类并不能使用子类特有方法。意味着一般情况下子类拥有的方法,属性,要比父类多。

    同理,View有的方法,属性同样较少,如果我们选择继承它,就得从零开始写起。但如果我们是想在某一控件上做功能扩展,我们可以选择继承于某一控件。

    如需要个一键清除输入内容的输入框(在源代码处会给出参考代码),就可以选择继承于EditView,在此基础上增加功能,当然,现在我们学习,只需要继承于View就可以了。

    一键删除,密码显示隐藏.gif

    重写父类一个onDraw方法,之后我们绘制东西,就是在该方法中绘制

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.View;
    
    public class XView extends View {
        public XView(Context context) {
            super(context);
        }
    
        public XView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        /**
         * 解释一下Canvas类,如果把XView类比作一个画板,那么Canvas就好比我们放在画板上的画纸,
         * 之后我们绘制的东西,就是呈现在该画纸上
         * @param canvas
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawColor(Color.parseColor("#03A9F4"));//使用java代码调用颜色
        }
    }
    
    
    

    在Canvas上调用drawColor方法给Canvas填充颜色,创建ViewActivity,在actiivty_view.xml下使用我们自定义的控件

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".module.canvasx.ViewActivity">
    
        <!--下面的是我们控件所在的包名,打出控件首字母就会有自动提示的-->
        <com.example.tonjies.view.module.canvasx.XView
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </android.support.constraint.ConstraintLayout>
    

    运行程序,确实和我们想的一样,画布上有了颜色

    Canvas颜色

    现在回过头开看看XView的两个构造方法

    /**
     * 只含有一个参数Context的构造方法,在代码创建组件时会被调用
     * 例如XView xView=new XView
     * L是自己封装的Log工具类,不清楚的可以查看我的一篇文章
     * https://www.jianshu.com/p/6ca3026fc991
     * @param context
     */
    public XView(Context context) {
        super(context);
        L.d("在代码创建时被调用");
    }
    
    /**
     * 在xml加载时被调用
     * @param context
     * @param attrs
     */
    public XView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);  
        L.d("在xml加载时被调用");
    }
    

    一个参数的构造方法会在创建组件时被调用,我们把xml里面的控件注释掉,在Activity中手动创建,打个日志运行进行验证

    public class ViewActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_view);
            XView view = new XView(this);
        }
    }
    

    一个参数的构造方法验证成功后,我们再把xml的控件注释回来,运行程序,发现构造二也打印出了log,证明我们的猜想确实是对的

    Paint

    Paint类好比是我们的画笔,接下来看一下Paint类常用方法,创建XViewb类

    public class XViewb extends View {
    
        private Paint paint;
    
        public XViewb(Context context) {
            super(context);
        }
    
        public XViewb(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            paint = new Paint();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            paint.setStyle(Paint.Style.FILL);//设置画笔类型
            paint.setStrokeWidth(200f);//设置画笔宽度
            paint.setColor(Color.BLACK);//设置画笔颜色
            canvas.drawPoint(0,0,paint);//设置坐标0,0
        }
    }
    

    声明了Paint类,在含有二个参数的构造方法中初始化Paint。在onDraw中通过setStrokeWidth设置画笔的宽度是200个像素,颜色是蓝色,最后调用canvas的drawPoint方法绘制了一个点

    而setStyle方法的作用是设置画笔的类型,一共有三种类型可以选择,分别是FILL(填充类型),STROKE (描边类型),FILL_AND_STROKE (填充且描边)

    画笔类型

    可以看到FILL填充,就只是填充内部的,而FILL_AND_STROKE在填充后又进行描边,会比单填充大一圈。

    canvas.drawPoint(0,0,paint);//设置坐标0,0,但是这个方法的坐标系正负和我们高中学的有所不同。

    坐标

    x轴:向右为正方向,向左为负方向

    y轴:向下为正方向,向上为负方向

    Path

    Path的作用是作为“路径”而存在的,有点类似photoshop里面钢笔工具画出来的路径,理解起来就是我们画出特定轨迹的路径,然后使用画笔工具对路径进行绘制操作

    • 绘制一个三角形
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.View;
    
    import com.example.tonjies.view.R;
    
    /**
     * Path类
     */
    public class XViewc extends View {
    
        private Paint paint;
    
        public XViewc(Context context) {
            super(context);
        }
    
        public XViewc(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            paint = new Paint();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            paint.setStyle(Paint.Style.STROKE);//设置画笔类型为描边
            paint.setStrokeWidth(8);//设置画笔宽度
            paint.setColor(getResources().getColor(R.color.colorAccent));
    
            //初始化Path
            Path path=new Path();
            path.moveTo(300,50);//moveTo方法是移动路径绘制起点位置,起点位置是(300,30)
            path.lineTo(500,50);//lineTo方法在起点(300,30)到(500,50)之间绘制一条线段
    
            //调用canvas的drawPath,把path和画笔作为参数传递进入
            canvas.drawPath(path,paint);
        }
    }
    

    很简单的案例,通过moveTo(300,50)设置起点,然后通过lineTo(500,50)绘制一条从点(200,200)到(500,50)的线段,而线段的颜色的宽度是由我们的画笔的属性决定的

    path绘制直线.png

    现在我们修改一下Path代码,运行程序

    //初始化Path
    Path path=new Path();
    path.moveTo(200,200);//moveTo方法是移动路径绘制起点位置,起点位置是(200,200)
    path.lineTo(400,200);//lineTo方法在起点(200,200)到(400,200)之间绘制一条线段
    path.lineTo(200,400);//linTo方法在起点(400,200)到(200,400)之间绘制一条直线,该直线在我们的图像中,就是斜线
    path.close();//close()方法会产生一条最短的线段闭合我们的路径,两点之间直线最短嘛,该直线在我们的图形中,就是点1(200,200)到点3(200,400)之间的直线
    
    path绘制三角形.png

    这样,我们就绘制了一个三角形,如果我们把画笔的模式变为FILL,就变成了一个实心的三角形

     paint.setStyle(Paint.Style.FILL);//设置画笔类型为填充
    

    代码和效果都很简单,就不贴图了

    这一小节就到这了,该小节仅仅只能作为快速了解,自定义控件包含的内容实在是很多,如果想要进一步的学习,可以查看我的Android文章推荐里面的推荐教程

    文本知识和图片部分来自随风飘扬的微笑的博客,感谢大佬的付出

    如果本篇文章对你有所帮助,麻烦给个喜欢,对于我来说,这是一种很好的鼓励,thank_

    谢谢,谢谢

    相关文章

      网友评论

        本文标题:Android自定义控件零基础简述「JAVA,基础」

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