其一数目也是储存在对象的三个属性当中,带大家来一步一步深远自定义View的社会风气

<input
type=”file”>——在vue中大家得以给input控件七个ref属性,然后大家能够利用this.$refs.(前面那玩意儿的属性值,其实正是3个锚点)去获取这么些控件,然后去调用那么些控件的files属性,我们就足以获得控件里面获取到的数据了。当然,他是贰个对象,那么些数额也是储存在指标的叁脾性能个中,具体什么的友爱去打印看看。然后那么些目的有个name属性,顾名思义,正是您收获的文书名,还有1个属性是length,大家能够采取那么些特性去看清控件到底里面有没有数据。就算你协调去做过,你会发觉有上面一种现象。

许多管敬仲觉得自定义View是王牌的表示,其实不然。大家觉得自定义View难很多景况下或许是因为自定义View涉及到了太多的类和API,把人搞得晕头转向的,那么今天大家就从最简便的绘图API开头,带我们来一步一步深刻自定义View的世界。

——场景场景场景——–

先来看看大家明天要兑现的多少个效果图:

1.先是次用控件获取一张图纸,我们来看控件获取到了数量

图片 1

2.次之次点开同样的控件,然而…..

任何职能很简短,正是在荧屏上海展览中心示一个时钟,该钟表能够自行走动。

3.自身吗也不选

OK,那就起来动工吧。

4.控件里面原来的数目被清空了,貌似一贯没来过这几个世上

1.准备工作

首先,要实现这几个时钟,作者得继续自View来本人绘制时钟,因为那种功用没有章程继续已有控件去完善职能。然后大家来探望大家那里须求哪些变量?在那篇博客中作者临时不打算介绍自定义属性以及View的衡量,那里本身只想介绍绘图API,所以View的轻重以及钟表表针的颜色等自己都一时先给3个恒定的值。OK,那么大家须要的变量首要便是上边多少个:

/**
     * 绘制表盘的画笔
     */
    private Paint circlePaint;

    /**
     * 绘制表盘数字
     */
    private Paint numPaint;
    /**
     * 绘制表心
     */
    private Paint dotPaint;
    /**
     * 时针
     */
    private Paint hourPaint;
    /**
     * 分针
     */
    private Paint minutePaint;
    /**
     * 秒针
     */
    private Paint secondPaint;
    /**
     * View宽度,默认256dp
     */
    private int width;
    /**
     * View高度,默认256dp
     */
    private int height;
    /**
     * 日历类,用来获取当前时间
     */
    private Calendar calendar;
    /**
     * 当前时针颜色
     */
    private int hourColor;
    /**
     * 当前分针颜色
     */
    private int minuteColor;
    /**
     * 当前秒针颜色
     */
    private int secondColor;
    /**
     * 时针宽度
     */
    private int hourWidth;
    /**
     * 分针宽度
     */
    private int minuteWidth;
    /**
     * 秒针宽度
     */
    private int secondWidth;

一起正是如此四个变量。

那明显不太融洽,于是动动脑子,你能够如此做

2.关于构造方法

世家看来,当小编一连View之后,系统必要自笔者完结它的构造方法,构造方法重要有四个,如下:

1.

public ClockView(Context context)

该构造方法是当小编在Java代码中new2个View的时候调用的。

2.

public ClockView(Context context, AttributeSet attrs)

该构造方法是当笔者在布局文件中添加一个View时调用的。

3.

public ClockView(Context context, AttributeSet attrs, int defStyleAttr)

很多管敬仲看到第多少个参数defStyleAttr之后,误以为倘诺小编在布局文件中写了style就会调用该构造方法,其实不然,这一个构造方法系统并不会融洽去调用(我们有趣味能够团结写一个style,然后在那一个格局中打字与印刷日志,看看该方式毕竟会不会调用),要由大家协调显式调用(能够在其次个构造方法中调用)。那么这里的defStyleAttr终归是何等意思呢?正如那么些参数的字面意思,它是我们为自定义的View内定的二个私下认可样式。(前边博客大家再来详细说一下这几个艺术)。

其它,还有2个高版本选拔的构造方法,我们那里暂不做牵线。

诚如景观下,大家要求在构造方法中完成都部队分先导化的操作,比如读取在XML文件中定义的质量,或然初叶化画笔等等,因为大家的控件既有或然是透过Java代码实例化的,也有只怕是在布局文件中通过xml添加的。如前所述,假若大家在Java代码中起初化控件,那么将调用第叁个构造方法,即便大家在xml布局文件中添加控件,那么将调用第①个构造方法。那时难点来了,那我们的初阶化控件的措施应该写在至极构造方法中吗?你能够按上边那种措施来写:

    public ClockView(Context context) {
        super(context);
        initView();
    }
    public ClockView(Context context, AttributeSet attrs) {
        super(context,attrs);
        initView();
    }

在八个构造方法中分别调用初阶化的点子,那种形式没有失常态,可是来得你的笔触没有眉目,参考Android提供的任何控件的源码,作者提议在起头化控件时遵照上边那种措施来写:

    //在代码中创建控件时调用
    public ClockView(Context context) {
        this(context, null);
    }

    //在布局文件中创建View时调用
    public ClockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

固然结果都相同,可是下面那种写法显得你思路很明显。

    data () {
       return {
          fileName: null
      }
   }

3.起始化控件

大家在预备工作中定义了许多变量,包括钟表的水彩,指针的颜料等等许多变量,那么接下去大家必要在initView那一个点子中来初叶化那个变量,以供下一步使用,OK,大家来看一望起头化代码:

    private void initView() {
        //获取当前时间的实例
        calendar = Calendar.getInstance();
        //时钟默认宽高
        width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
        height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
        //初始化表针的颜色
        hourColor = Color.RED;
        minuteColor = Color.GREEN;
        secondColor = Color.BLUE;
        //初始化表针的宽度
        hourWidth = 8;
        minuteWidth = 5;
        secondWidth = 2;
        //初始化各种画笔
        circlePaint = new Paint();
        //去锯齿
        circlePaint.setAntiAlias(true);
        //设置画笔颜色
        circlePaint.setColor(Color.GREEN);
        //设置画笔style为描边
        circlePaint.setStyle(Paint.Style.STROKE);
        //设置描边的宽度
        circlePaint.setStrokeWidth(6);
        dotPaint = new Paint();
        dotPaint.setAntiAlias(true);
        dotPaint.setColor(Color.RED);
        dotPaint.setStyle(Paint.Style.FILL);
        numPaint = new Paint();
        numPaint.setColor(Color.RED);
        numPaint.setAntiAlias(true);
        //文本对齐方式
        numPaint.setTextAlign(Paint.Align.CENTER);
        hourPaint = new Paint();

        hourPaint.setColor(hourColor);
        hourPaint.setStyle(Paint.Style.FILL);
        hourPaint.setStrokeWidth(hourWidth);
        minutePaint = new Paint();
        minutePaint.setColor(minuteColor);
        minutePaint.setStyle(Paint.Style.FILL);
        minutePaint.setStrokeWidth(minuteWidth);
        secondPaint = new Paint();
        secondPaint.setColor(secondColor);
        secondPaint.setStyle(Paint.Style.FILL);
        secondPaint.setStrokeWidth(secondWidth);
    }

率先是获得三个当下日子的实例,因为自个儿须要遵照手提式有线电话机上的时光来呈现钟表的年华,其次便是对表针的各个质量和画笔进行起初化,那里的东西都很简单,笔者就不再一一细说,大家看代码注释,相信都能看得懂。


4.制图钟表

上边装有的行事做完事后,接下去正是绘制钟表了,绘制工作我们放在了onDraw方法中履行,在自定义控件时,假如该控件是大家三番伍回自View来兑现的,那么基本上那一个控件即是亟需大家本人来绘制了。

OK,那我们来探视钟表的绘图吧。

钟表不算复杂,可是大家也亟需一步一步来:

先是是绘制表盘,这么些最简易:

        //1.圆心X轴坐标,2.圆心Y轴坐标,3.半径,4.画笔
        int radius = width / 2 - 10;
        //画表盘
        canvas.drawCircle(width / 2, height / 2, radius, circlePaint);

radius表示表盘的半径,通过drawCircle绘制1个圆环,多个参数分别是圆环的为主点坐标,圆环的半径以及绘制圆环的画笔。

圆环画好以往,那么接下去就是绘制表心了,也正是表面正着力非凡荧光色的圆心。

canvas.drawCircle(width / 2, height / 2, 15, dotPaint);

很不难吗。

OK,四个最简便的东东画完之后,那么接下去就是绘制表盘的年月刻度了,时间刻度的绘图除了数字之外,还有二个深湖蓝的短线,大家一共要画十二个那种东西,那么那个要怎么绘制呢?思路有过多,你能够依据高级中学的数学知识,总括出每三个数字的坐标以及每八个短线先导地点和了结地点的坐标,然后绘制出来,毫无疑问,那种办法的总结量太大,那大家那里运用三个简短的章程:笔者老是只在十二点的10分地方上拓展绘图,如果必要绘制一点,那么笔者把画布逆时针转动30度到十二点的岗位,然后画上1和1个短线之后再将画布顺时针旋转30度,要是是绘制2点,那么本身把画布逆时针旋转60度到十二点的职位,然后绘制上2和1个短线,绘制完毕之后再将画布顺时针旋转60度,思路就是如此,上边大家来看看代码:

        for (int i = 1; i < 13; i++) {
            //在旋转之前保存画布状态
            canvas.save();
            canvas.rotate(i * 30, width / 2, height / 2);
            //1.2表示起点坐标,3.4表示终点坐标,5.画笔
            canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - radius + 10, circlePaint);
            //画表盘数字1.要绘制的文本,2.文本x轴坐标,3.文本基线,4.文本画笔
            canvas.drawText(i + "", width / 2, height / 2 - radius + 22, numPaint);
            //恢复画布状态
            canvas.restore();
        }

自身用3个循环来绘制那十1个刻度,在每趟旋转画布在此之前,小编都通过一个canvas.save()方法来保存画布当前的场地,保存之后再对画布进行旋转操作,旋转实现之后就是画线画数字,那个都很简单,在绘制达成现在,作者索要调用canvas的restore()方法,该格局能够让画布恢复生机到旋转在此之前的角度。一般情状下,canvas.save()方法和canvas.restore()方法都以成对出现的,这点大家要注意。

OK,那些事物都绘制实现之后,接下去就该绘制表针了,表针的绘图思路和上边一样,也是先旋转表盘,然后绘制表针,绘制实现以后,再把表盘旋转回此前的景色。这里笔者就不再详细表达了,我们看代码:

        //获得当前小时
        int hour = calendar.get(Calendar.HOUR);
        canvas.save();
        //旋转屏幕
        canvas.rotate(hour * 30, width / 2, height / 2);
        //画时针
        canvas.drawLine(width / 2, height / 2 + 20, width / 2, height / 2 - 90, hourPaint);
        canvas.restore();

        int minute = calendar.get(Calendar.MINUTE);
        canvas.save();
        canvas.rotate(minute * 6, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 + 30, width / 2, height / 2 - 110, minutePaint);
        canvas.restore();
        int second = calendar.get(Calendar.SECOND);
        canvas.save();
        canvas.rotate(second * 6, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 + 40, width / 2, height / 2 - 130, secondPaint);
        canvas.restore();

OK,全数的事情做完以往,大家得以在布局文件中添加如下代码,来查阅大家的行事做得怎么着:

    <org.mobiletrain.clockview.ClockView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

添加实现以后,运维,不出意外的话,你的App上应该早就显得了二个时钟了,但是那个时钟是上行下效的,那么大家该怎么让时钟动起来呢?其实很简答,大家只供给每隔一秒重新赢得calendar实例,然后重绘钟表即可,所以,在onDraw方法的开首和了结,我们还要分别增进如下两行代码:

1.开端处添加:

calendar = Calendar.getInstance();

那行代码用来赢得最新的光阴的实例

2.结束处添加:

postInvalidateDelayed(1000);

这行代码用来重绘钟表,可是重绘是在1秒今后。

OK,至此,大家的自定义钟表就完事了,完整的代码应该是以此样子:

/**
 * Created by wangsong on 2016/3/29.
 */
public class ClockView extends View {

    /**
     * 绘制表盘的画笔
     */
    private Paint circlePaint;

    /**
     * 绘制表盘数字
     */
    private Paint numPaint;
    /**
     * 绘制表心
     */
    private Paint dotPaint;
    /**
     * 时针
     */
    private Paint hourPaint;
    /**
     * 分针
     */
    private Paint minutePaint;
    /**
     * 秒针
     */
    private Paint secondPaint;
    /**
     * View宽度,默认256dp
     */
    private int width;
    /**
     * View高度,默认256dp
     */
    private int height;
    /**
     * 日历类,用来获取当前时间
     */
    private Calendar calendar;
    /**
     * 当前时针颜色
     */
    private int hourColor;
    /**
     * 当前分针颜色
     */
    private int minuteColor;
    /**
     * 当前秒针颜色
     */
    private int secondColor;
    /**
     * 时针宽度
     */
    private int hourWidth;
    /**
     * 分针宽度
     */
    private int minuteWidth;
    /**
     * 秒针宽度
     */
    private int secondWidth;

    //在代码中创建控件时调用
    public ClockView(Context context) {
        this(context, null);
    }

    //在布局文件中创建View时调用
    public ClockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        //获取当前时间的实例
        calendar = Calendar.getInstance();
        //时钟默认宽高
        width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
        height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
        //初始化表针的颜色
        hourColor = Color.RED;
        minuteColor = Color.GREEN;
        secondColor = Color.BLUE;
        //初始化表针的宽度
        hourWidth = 8;
        minuteWidth = 5;
        secondWidth = 2;
        //初始化各种画笔
        circlePaint = new Paint();
        //去锯齿
        circlePaint.setAntiAlias(true);
        //设置画笔颜色
        circlePaint.setColor(Color.GREEN);
        //设置画笔style为描边
        circlePaint.setStyle(Paint.Style.STROKE);
        //设置描边的宽度
        circlePaint.setStrokeWidth(6);
        dotPaint = new Paint();
        dotPaint.setAntiAlias(true);
        dotPaint.setColor(Color.RED);
        dotPaint.setStyle(Paint.Style.FILL);
        numPaint = new Paint();
        numPaint.setColor(Color.RED);
        numPaint.setAntiAlias(true);
        //文本对齐方式
        numPaint.setTextAlign(Paint.Align.CENTER);
        hourPaint = new Paint();

        hourPaint.setColor(hourColor);
        hourPaint.setStyle(Paint.Style.FILL);
        hourPaint.setStrokeWidth(hourWidth);
        minutePaint = new Paint();
        minutePaint.setColor(minuteColor);
        minutePaint.setStyle(Paint.Style.FILL);
        minutePaint.setStrokeWidth(minuteWidth);
        secondPaint = new Paint();
        secondPaint.setColor(secondColor);
        secondPaint.setStyle(Paint.Style.FILL);
        secondPaint.setStrokeWidth(secondWidth);
    }

    //绘制View
    @Override
    protected void onDraw(Canvas canvas) {
        calendar = Calendar.getInstance();
        //1.圆心X轴坐标,2.圆心Y轴坐标,3.半径,4.画笔
        int radius = width / 2 - 10;
        //画表盘
        canvas.drawCircle(width / 2, height / 2, radius, circlePaint);

        canvas.drawCircle(width / 2, height / 2, 15, dotPaint);
        for (int i = 1; i < 13; i++) {
            //在旋转之前保存画布状态
            canvas.save();
            canvas.rotate(i * 30, width / 2, height / 2);
            //1.2表示起点坐标,3.4表示终点坐标,5.画笔
            canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - radius + 10, circlePaint);
            //画表盘数字1.要绘制的文本,2.文本x轴坐标,3.文本基线,4.文本画笔
            canvas.drawText(i + "", width / 2, height / 2 - radius + 22, numPaint);
            //恢复画布状态
            canvas.restore();
        }
        //获得当前小时
        int hour = calendar.get(Calendar.HOUR);
        canvas.save();
        //旋转屏幕
        canvas.rotate(hour * 30, width / 2, height / 2);
        //画时针
        canvas.drawLine(width / 2, height / 2 + 20, width / 2, height / 2 - 90, hourPaint);
        canvas.restore();

        int minute = calendar.get(Calendar.MINUTE);
        canvas.save();
        canvas.rotate(minute * 6, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 + 30, width / 2, height / 2 - 110, minutePaint);
        canvas.restore();
        int second = calendar.get(Calendar.SECOND);
        canvas.save();
        canvas.rotate(second * 6, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 + 40, width / 2, height / 2 - 130, secondPaint);
        canvas.restore();
        //每隔1秒重绘View,重绘会调用onDraw()方法
        postInvalidateDelayed(1000);
    }
}

以上。

if (this.$refs.imgFile.files.length !== 0) {
   this.fileImg = this.$refs.imgFile.files
} else {
   this.$refs.imgFile.files = this.fileImg
   return
 }

上边是vue的写法,因为方今用vue写项目,所以偷个懒。用原生的话做的章程同样

好了,今后您会意识,不会再有上边那种非友好的用户体验了,当然那几个同仁一视,有人说那是个fetch,小编觉得它很多时候是个bug…..

大家随后唠

接下去,我们会扭转三个图形对象,你能够用createElement的措施或然用new
Image的艺术,那几个不纠结

请看那里

let imgRender = new FileReader()//用来把文件读入内存,并且读取文件中的数据。FileReader接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据
imgRender.readAsDataURL(file)//将文件读取为DataURL

 具体文献链接:http://blog.csdn.net/zk437092645/article/details/8745647

如果您问怎么是dataurl,作者提议你协调先去找小说看看啊,小编那有一篇不错的稿子链接你能够看看:http://www.webhek.com/post/data-url.html

然后,大家选拔canvas,先安装大小,于是能够这样做

let canvas = document.createElement('canvas')
canvas.width = targetWidth
canvas.height = targetHeight

本人纪念canvas对象私下认可的小幅是300,高度是150,你协调可以打字与印刷看看

下一场大家做上边一件事

let canvasCtx = canvas.getContext('2d')

为了省去有些同学去翻资料,小编解释下啥意思===>钦点了您想要在画布上绘制的花色。当前唯一的官方值是
“2d”,它钦点了二维绘图,并且导致那些法子再次来到3个环境目的,该对象导出3个二维绘图
API(那是网上的表达,作者只是个搬运工)。

接下来大家用这些指标的fillRect方法,能够设定这么些条件指标的横坐标、纵坐标、宽度、中度。然后是最后一步,用drawImage方法向画布上绘制图像、画布或录像。就像是下边

canvasCtx.fillStyle = '#fff'
canvasCtx.fillRect(0, 0, canvas.width, canvas.height)// set the default background color of png  to white
canvasCtx.drawImage(图片对象files[0], 0, 0, targetWidth, targetHeight)

OK,那面包车型大巴手续相当粗略有木有。总的来说,大家照旧用canvasCtx环境指标做一些’动作’

接下去的动作就很简短了,我们看上边

let picBase64 = canvas.toDataURL('image/jpeg', 1)//canvas里面是二进制二进制2222222222222
let fd = new FormData()
let blob = ImgUtil.base64ToBlob(picBase64)//不是blob,你传不了,这里不多解释这个,网上解释很多----你可以用atob()这个方法来,但是这个方法有挺大的缺陷,不过兼容性很好了,而且
你要对它进行切割切割,因为前面会有些emmit----》九九归一,来个new Blob()统统搞定
fd.append('pic', blob)

 OK,到这里,你可以拿上你的接口,把那东西甩过去了。当然,并不是兼备情形都以那样子,你得和您的后端小伙伴协定好,到底要如何的数目。

相关文章