新浦京81707con > 功能介绍 > Android自定义控件之圆形时钟,怎样画出一个好看

原标题:Android自定义控件之圆形时钟,怎样画出一个好看

浏览次数:123 时间:2020-03-01

图片 1loading.gif

图片 2

自定义属性

率先values文件下,新建attrs.xml的xml文件。表明能源类型为子标签为

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TopBar">
        <attr name="title" format="string"/>
        <attr name="titleTextSize" format="dimension"/>
        <attr name="titleTextColor" format="color"/>
        <attr name="leftTextColor" format="color"/>
        <attr name="leftText" format="string"/>
        <attr name="leftBackground" format="reference|color"/>
        <attr name="rightTextColor" format="color"/>
        <attr name="rightText" format="string"/>
        <attr name="rightBackground" format="reference|color"/>
    </declare-styleable>
</resources>

//此中<declare-styleable>元素的name属性的值,正是此组自定义属性的器皿名.

而 < attr > 成分表示的name属性表示View 控件的属性名,format属性表示帮忙的项目 .

要在构造文件中接纳自定义属性呢,首先要要为那个自定义属性导入七个命名空间.

xmlns:app="http://schemas.android.com/apk/res-auto"

下一场在具体的控件里,就能通过app:属性名 找到自定义属性了.

浅析具体设置那三个自定义属性,如下所示:

public TopBar(Context context, AttributeSet attrs) {
  super(context, attrs);
  getAttrs(attrs);
  setView(context);
}
 private void getAttrs(AttributeSet attrs) {
   TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.TopBar);
   mTitleText = ta.getString(R.styleable.TopBar_title);
   mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize,10);
   mTitleTextColor = ta.getColor(R.styleable.TopBar_titleTextColor,0);
   mleftBackgound = ta.getDrawable(R.styleable.TopBar_leftBackground);
   mleftColor = ta.getColor(R.styleable.TopBar_leftTextColor,0);
   mleftText = ta.getString(R.styleable.TopBar_leftText);
   mRightColor = ta.getColor(R.styleable.TopBar_rightTextColor,0);
   mRightText = ta.getString(R.styleable.TopBar_rightText);
   mRightBackgound = ta.getDrawable(R.styleable.TopBar_rightBackground);
   ta.recycle();
}
 public void setView(Context context) {
    mleftButton = new Button(context);
    mRightButton = new Button(context);
    mTitle = new TextView(context);

    mTitle.setText(mTitleText);
    mTitle.setTextColor(mTitleTextColor);
    mTitle.setTextSize(mTitleTextSize);
    mTitle.setGravity(Gravity.CENTER);
    mTitleLP = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);
    mTitleLP.addRule(RelativeLayout.CENTER_IN_PARENT);

    mTitle.setLayoutParams(mTitleLP);

    mleftLP = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);
    mleftLP.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    mleftButton.setText(mleftText);
    mleftButton.setTextColor(mleftColor);
    mleftButton.setBackground(mleftBackgound);
    mleftButton.setLayoutParams(mleftLP);

    mRightLp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);
    mRightLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    mRightButton.setText(mRightText);
    mRightButton.setTextColor(mRightColor);
    mRightButton.setBackground(mRightBackgound);
    mRightButton.setLayoutParams(mRightLp);


     addView(mTitle);
     addView(mRightButton);
     addView(mleftButton);
     setOnclik(mRightButton,mleftButton);
 }

因此结构函数提供的AttributeSet类的目的,getContext(卡塔尔.obtainStyledAttributes(AttributeSet set, int[] attrs卡塔尔; 把AttributeSet对象剖析到自定义属性 容器里(即对应昂Cora.styleable.TopBar) ,获得贰个TypedArray类的指标,调用getString(CRUISER.styleable.TopBar_title, 0 State of Qatar,别的品质相仿,参数一为索引名,传入自定义属性中的名字就好(必要求以-连接卡塔尔国,参数二为未有到手到值时的暗许值。

转发请注解出处

好了,回到我们的大旨上来,画笔和画布都有了,那么难点来了,,,开采机本事哪家强。。。。。日。。再来一遍,,那么难点来了,假设是您想要在现实生活中画一个挂钟,你认为都得要画什么吗?笔者想时辰候大家一定都有在和睦手上画钟表的经验吗。首先,当然得有三个边框吧,然后是圆心、刻度以致数字,当然还会有最要紧的指针,这也是组成石英钟最基本的成分,相信你及时必定画的极漂亮貌。那么在Android中到底该怎么去画吗。接下来,小编就带大家一块走访,那一个事物是怎么一步步画在二弟大上的。

Paint 画笔的施用

Paint对象呢为用于在Canvas上画东西的笔;

常用方法:

setAntiAlias(boolean aa);

此用于用于安装是不是展开抗锯齿,为true呢为张开,false为不展开。

setStyle(Paint.Style style);

此用于安装画笔的风骨。默以为 FILL(填满) ;
STROKE表示笔为空心,仅仅画边。FILL_AND_STROKE表示宗旨部分为空,外围填满。

setStrokeWidth(float width);

此格局用于安装当画笔为STROKE时,延伸出来的宽窄。

setStrokeCap(Paint.Cap cap);

此措施用于安装经常用来弧线,设置尾部和尾巴是圆角,默以为直角.

setColor(int color);

此办法用于安装画笔的颜色.

setTextSize(float textSize) ;
  • ###### 第一步

如上海教室所示,我们把坐标原点移到圆心,那样只要大家要画图棕黄色刻度线,其实就很简短了。初始坐标和终点坐标的Y轴坐标均为0,开端坐标的X轴坐标为半径减去刻度线长度,而终点坐标的X轴坐标就是半径。如何,那样画一条刻度线是或不是挺简单的,相信你早晚能画好。好,接下去大家再画一条,然而在画早前,大家得做叁个小小的动作,正是把坐标系旋转一下。如下图:

Canvas画布的接受

暗许坐标:

图片 3

Canvas

Canvas类也就是三个矩形画布,私下认可0,0坐标是左上角。用到的坐标都以画布上的(即视图坐标系)。要求自定义View上的内容动起来吧,正是开外界接口,然后重绘(即重调用invalidate(卡塔尔国,重绘,但Canvas上的尺码必需求安装好变量)。
其常用艺术有,draw( 卡塔尔(قطر‎方法最终二个参数都为Paint 对象:

  • drawRect(RectF rect,Paint paintState of Qatar;//在画布上制图三个矩形;
    • react 对象为描述必要在Canvas上区域;
      参数一意味着矩形左侧的X坐标,余下多个同理。
save( );             

//此格局用于保存当前画布的景况,平时多用来旋转画布的时候

restore();

///此方法用于苏醒画布,即复苏到save( 卡塔尔方法存入时的场地,但在画布上画的事物不会被注销。

rotate(float degrees, float px, float py);

//此方法用于旋转画布,参数一为旋转的角度(正数为顺时针方向转,负数为逆时针State of Qatar,参数二,三画布旋转的轴点. 当画布旋转时呢,其的坐标也是接着一同旋转了,所以就意味着早晚要此Canvas的主干坐标点来旋转,不然转了后内容会舍弃。当确定点后,是以此点的上直线为O度. 当转动到对应的角度后,又以极其角度会0度。

相像的话,三次转动 对应一个内容绘制。下一次转动并不会把上次绘制的源委也转动了.
多用来圆盘类的自定义View,鲜明三个地方的内容就足以转动绘制,省去多次规定坐标.

 RectF rectf =new RectF(float left,float top,float reight,float bottom);                

drawPath(Path path,Paint paint);

//在画布上绘制八个Path图形(即图像的大致),图形复杂时就用那些。

  • Path类常用方法用:

moveTo(float x,float y卡塔尔; //设置下一次一而再再而三操作的坐标(移动的起源)。如不设置呢为Canvas的0,0 坐标。
lineTo(float x,float yState of Qatar;//设置上个点到此点用直线连接。
close(State of Qatar;连接第一点到最终一个点,产生闭合。
越来越多内容查看此

drawBitmap(Bitmap bitmap,float left , float top , Paint paint) ;

//其实呢就是贴图。
因为一张图纸长宽料定是规定的,所以鲜明左上角的坐标就OK 了。

 drawLine(float startx , float starty , float stopx , float stopy , Paint paint) ;                               

//画线,当x坐标的胚胎和终止的坐标不改变时,变化的为Y时,画出来的时竖线。反之横线。
当x和y都以变的,画出来的便是斜线。

drawPoint(float x, float y, Paint paint); 

//表示画点。

drawText(String text, float x, floaty, Paint paint) ;

//绘制文本,x,y坐标用于鲜明文字左上角的坐标。

drawOval(RectF oval, Paint paint);

//此为画椭圆,参数一用于鲜明椭圆外接矩形(用于分明椭圆能画多大卡塔尔国.

drawCircle(float cx, float cy, float radius,Paint paint);

//此为画园,参数一二为明确圆的骨干坐标。参数三为半径。

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) ;

//画弧,参数一用于明显弧能画多大,参数二为弧的开首角度,参数三为绘制的角度,(弧会顺时针绘制)。参数四为是不是把所画弧的初步点停止点连接到弧心,为false弧线,true就封。

canvas.rotate(twoStepValue);
public class TimeView extends View{ private Context mContext; private Paint mPaint; public TimeView(Context context) { super; this.mContext = context; initPaint(); } public TimeView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; initPaint(); } /** * 初始化画笔 */ private void initPaint(){ mPaint = new Paint(); //抗锯齿 mPaint.setAntiAlias; mPaint.setColor(Color.BLACK); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth; } @Override protected void onDraw(Canvas canvas) { //画具体内容 }}

自定义View 三大流程

平常要写自定义View呢

onMeasure( int widthMeasureSpec, int heightMeasureSpec) ; //测量;
onLayout(boolean changed, int left, int top, int right, int bottom) ; //布局;
onDraw(Canvas canvas);//绘制

onMeasure( State of Qatar方法都得重写,因为系统暗中同意对wrap_content的属性值管理是match_parent.所以想扶持此属性就务须复写此办法来内定wrap_content的值。

@Override
protected  void  onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
   setMeasuredDimension(measureHW(widthMeasureSpec,150) , measureHW(heightMeasureSpec,200));
}

private  int  widthMeasure(int  measureSpec , int defultV) {
   int result = defultV ;
   int mode = MeasureSpec.getMode(measureSpec);
   int size = MeasureSpec.getSize(measureSpec);

   if (mode == MeasureSpec.EXACTLY) {
         result = size;
   }else if (mode == MeasureSpec.AT_MOST) {
         result = Math.min(result , specSize);
   } 
   return result;
}

里面使用到的MeasurSpec类,为支援度量View的, onMeasure( State of Qatar方法中传递步入的值,是三个34位的int 值.解析出这几个值就能够得到此View的形式和 大小.日常用到的二种格局

EXACTLY:即标准情势,View 的layout_height 和layout_width属性内定为准确数字依旧match_parent时,View使用的正是EXACTLY格局。

AT_MOST: 即最大值情势,当 View 的layout_height 和 layout_width 属性钦定为wrap_content.就是此格局 意指 控件的高低随内容改造,不过无法超越父View

相同的话的话,不写ViewGroup的话onLayout是毫无i复写的,未有满含别的View所以也就绝不总计其子View 的构造坐标。

onDraw( 卡塔尔国 ,此措施正是最后展现到显示器上的内容. 在绘制自定义View时吗,记得必定要把其拆分开,然后三个个的绘图 .

哈。。。自定义View真的轻便, 一些光彩夺目的View看着很巧妙,其实只要把团结的思路捋清楚了一步一步的去做纯属能做出来,进程十分惨重但写出来了也很有成就感不是~接下来自身享受的是几个谈得来画的望着很玄妙(笔者反正是认为挺玄妙的 = =!)其实炒鸡轻巧的自定义Loading。上效果图

GitHub地址:

滑动移动间距的乘除

@Override 
public boolean onTouchEvent(MotionEvent event) {
        switch(event.getAction( ) ) {
                case MotionEvent.ACTION_DOWN:
                 lastx = (int) event.getX( );
                break;

                case MotionEvent.ACTION_MOVE:
               movex = (int) event.getX()-lastx;  //获取当前移动了多少距离;
                break;

                case MotionEvent.ACTION_UP:
                //处理输入的离开的事件.
                break;
        }
        return true;
}

如果在ACTION_MOVE中有重绘视图时,必须求终极重复赢伏贴前的坐标,下一次再实行到ACTION_MOVE状态手艺科学计算偏移量,不然lastx一向是DOWN状态是的坐标.

X轴: 假使总计出活动的值为-值,那么正是向左滑,为正在,就是向右滑。

Y轴:假如总计出活动的值为-值,那么正是发展滑,为正值,正是向下滑。

x坐标恒久为0,动态的改变y的坐标进而达成大家想要的作用。

图片 4

野趣是将画布旋转twoStepValue度,twoStepValue这些值是经过

图片 5图片 6图片 7

  • ###### 第二步

好了,数字也总算画好了,接下去就只剩下指针了,指针分秒针、分针和时针,知道一种怎么画就足以。其实超粗略,这里本身直接调用drawLine(State of Qatar方法,代码如下:

oneStepValue =  animation.getAnimatedValue; twoStepValue =  animation.getAnimatedValue; threeStepValue =  animation.getAnimatedValue; invalidate();

因为我们各种指针的旋转角度都分裂,所感觉了防止相互影响,我们把各类指针画在canvas.save(State of Qatar和canvas.restore(State of Qatar之间,十三分每一种指针都画在差别的图层上,最究竟总为一张图。

canvas.drawCircle(0, -((width / 2 - insideRectWidth) / 2   insideRectWidth)   oneStepValue, threeStepValue, mPaint);
@Overrideprotected void onDraw(Canvas canvas) { //圆形边框 mPaint.setStrokeWidth; canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 3, mPaint); //圆心 mPaint.setStrokeWidth; canvas.drawPoint(getWidth() / 2, getHeight() / 2, mPaint); //设置刻度线线宽 mPaint.setStrokeWidth; //将坐标原点移到圆心处 canvas.translate(getWidth()/2,getHeight; for (int i = 0; i < 360; i  ) { //这里刻度线长度我设置为25 canvas.drawLine(getWidth() / 3-25, 0,getWidth() /3, 0, mPaint); canvas.rotate; }}
for (int i = 0; i < 4; i  ) { canvas.rotate; mPaint.setColor(colors[i]); canvas.drawCircle(0, -((width / 2 - insideRectWidth) / 2   insideRectWidth)   oneStepValue, threeStepValue, mPaint); }

此处自身回顾说一下那多少个法子,第1个是坐标系的运动,传入的五个参数,分别为移动后坐标原点的X、Y坐标,说白了正是你想把坐标原点移到哪个点就传出哪个点;第二个章程是把坐标系旋转一定角度,传入正数则顺时针转,负数则相反。第四个艺术是绕着传播的点旋转一定度数。好了,知道了那多少个方法未来再画刻度线是否有一些思路了啊。大家明白,要想求出全部刻度的初始与终极坐标很复杂,也不太现实。但求一条刻度的坐标依旧好求的。为了坐标表示方便大家移动一下坐标系,即调用canvas.translate(getWidth()/2,getHeight将坐标原点移到圆心处。

上两步成功之后4个圆确实是动起来了,不过也只是绕着控件附近活动而不会向控件中央移动,那不是大家想要的成效,上面说下向主导移动的思绪在Android中画出来的圆是由x,y坐标构成圆心加上半径组成的。。。所以呢,大家只须求退换他的y坐标就好啊是或不是炒鸡轻易!!!

第一,大家得和谐定义三个类取名为TimeView,让其三番两次View,然后创造布局方法,最后大家要覆写onDraw(Canvas canvas)情势,大家具体的油画逻辑就在此个方法中。具体代码如下:

  • ###### 第四步

下面的代码依然好通晓的,大家创立二个巡回,每循环一回就写个文字,并且将坐标系顺时针旋转30度,此中我们得以看来,大家创制了叁个矩形,然后我们调用mPaint.getTextBounds(String text,int start,int end,Rect textBoundState of Qatar将文字的边框存入此中,这一个形式传入多少个参数,第二个为大家要画的字符串,第二四个参数分别为这一个字符串的起来角标和截止叫角标,最终二个为矩形。那样我们就足以把那个矩形精晓为这些字符串的边框,有了边框大家就足以精晓这么些字符串的众多参数,比方上下左右的坐标,以致字符串的宽高端。那样当大家画数字时,它的X坐标便是文字宽度的四分之二,注意别忘了负号。好了我们来看下效果怎么着:

  • ###### 第三步
<com.example.administrator.timeviewdemo.TimeView android: android:layout_width="300dp" android:layout_height="300dp"/>

最近的View已经很雅观了~可是还是可以在微小的点缀下的, threeStepValue以此变量是还是不是很熟识对的,在步骤三涌出过,他的本名称叫半径,是叁个动态的半径(那个半径是算出来的,不贴怎么算的了后头有源码)。。校勘她,就可以忽大忽小了

图片 8

下边初始说一下画这几个loadingView的经过。

能够见见圆内被填充了,那下你应有了然FILL和STROKE的界别了啊。好了我们来看下叁个

咱俩在onDraw方法里面写三个for循环,循环4次每循环1次画二个圆然后将画布旋转90°那样4个圆就画出来了。

只能用两字形容“完美”。

PropertyValuesHolder twoAnimation = PropertyValuesHolder.ofInt(TWOANIM, 0, 359);

好了,知道了怎么写文字后,大家就足以在石英钟上写上大家要的拾个数字了,一共十七个数字,多少个圆360度,所以每一个30度写三个字。那样大家就能够用事情未发生前的艺术,没写完贰个数,就将坐标系旋转30度。代码如下:

4个方向的圆已经画出来了怎么着让她动起来吧?我们先看一下这行代码

图片 9

完成了~~作者通晓写随笔要用马克down了!确实很温婉啊又学到了新知识协同提高!加油未来自个儿只怕每一周都会写点东西,嗯。。不管写的好倒霉小编都要写,再不怕希望对各位看官微微有那么点协助小编就很欢乐了~

这些年,Computer忽地罢工了,搞了自己好长期才弄好。。所以写那篇小说贻误了很短日子。废话非常少说后天本人给我们带给二个近年来友好造的轮子——自定义石英钟。对自定义控件风野趣的相爱的人能够看看,具体内容作者会尽量讲的详细。先看一下功力图:

本文由新浦京81707con发布于功能介绍,转载请注明出处:Android自定义控件之圆形时钟,怎样画出一个好看

关键词: 圆形 Android 自定义 画出 好看

上一篇:简单一招,如何用修图软件修出漂亮的手机照片

下一篇:没有了