实践自定义UI—View

目前IOS和Android两个系统的交互设计都在相互的借鉴,所以有的时候我们需要在Android系统中实现IOS的一些UI效果,那我们就必须自己实现啦(没有现成的控件)。现在也看到很多公司也把能够自定义UI放到招聘要求中,可见我们还是要学习如何去自定义。当然我们自定义UI的过程中,可以让我们对Android系统的一些机制理解的更加透彻。那么自定义UI真的很难吗,我感觉没有那么难,只要多练习,自然就可以了。按照我的理解,其实我们自定义UI是可以通过这三种方法实现:

1.继承View,直接在Canvas上面绘制。

2.继承ViewGroup,根据ViewGroup的绘制流程实现自己需要的效果。

3.利用已有的UI控件(RelativeLayout,LinearLayout,FrameLayout....),继承改造或者组合使用等。

接下来就以上的方法,一个一个实践来练习吧!

自定义UI(利用View)

利用View实现自定义主要是继承View并利用OnDraw(Canvas canvas)方法绘制自己需要的UI,利用canvas主要可以绘制矩形(包括圆角矩形)、圆、点、线、扇形等,同时还可以根据类Path设置需要的路径,利用Canvas将Path绘制出来。具体的使用通过实践学习吧。这里我们还要关心View中的OnMeasure()方法,这个方法主要是设定我们当前这个View的大小。关于View中的这些方法的分析可以看看这篇文章,分析的比较详细。好了,还是实战吧(在实战中遇到问题不断的解决,自然对很多东西就了解了,总是看理论的东西还是理解的不透彻哦),今天利用View实现如下的效果(gif 效果不是很好0_0,这里我们只分析第二个效果图,其他的读者可以自己扩展实现):

效果图

分解效果图

任何复杂的事情都要学会分解成多个简单的事情去处理。动画效果的某个瞬间的静态UI如下所示:

运动的某个瞬间

通过这个静态的UI,可以看出它的组成很简单:一个大圆,一个实心的小圆————这个小圆的中心点是在大圆的圆环上。这样就把这个静态的UI分解为:一个大圆和一个小圆。

接下来想想怎么让实心小圆动起来呢?前面说了,小圆的中心在大圆的圆环上,如果这个中心不停的沿着大圆的圆环上走,不就动起来的。怎么沿着走呢,看看下面的图!

坐标图

上图我们绘制了小球(实心小圆)的中心位置,这里我们选取的顺时针方向为正方向,并且0度角为X轴正方向。这里选取了45度角的一个静态分析,假设定义一个变量为angle,当这个angle不断的从0到360变化时,小球就是沿着大圆跑了。根据上面的图和前面的分析,应该比较清晰的知道原理了吧_

实现分解效果图

这里将实现上面分解的结果啦,应该很简单的!

1.绘制圆环

在onDraw(Canvas canvas)这个方法中利用canvas绘制,直接上代码:

private void drawBigCircle(Canvas canvas){
    canvas.drawCircle(rectF.centerX(), rectF.centerY(), getBigCircleRadius(), mCirclePaint);
}

(这里的rect变量主要是利用Rect累框定绘制圆的范围)这里主要是利用了canvas的方法(当然,绘制circle的方法还有其他几个方法可以调用,根据自己的需求):

drawCircle(float cx, float cy, float radius, @NonNull Paint paint)

简单介绍一下参数,这里cx,cy表示的是圆心位置;radius表示圆半径的大小,paint主要是画笔,可以设置颜色等。这个应该比较简单吧+_+

2.绘制实心小圆——小球

还是直接看代码,然后分析_

double sweepAngle = Math.PI/180 * 45;
//caculate the circle's center(x, y)
float y = (float)Math.sin(sweepAngle)*(getBigCircleRadius());
float x = (float)Math.cos(sweepAngle)*(getBigCircleRadius());
int restoreCount = canvas.save();
//change aix center position
canvas.translate(rectF.centerX(), rectF.centerY());
canvas.drawCircle(x, y, mAccBallRadius, mAccBallPaint);
canvas.restoreToCount(restoreCount);

这里的第一步是计算角度,第二是计算实心小圆的中心位置,这两步根据上面分解章节的数学计算应该很好理解的。第三步是绘制实心小球,这里实现实心是通过Paint的方法setStyle(Paint.Style.FILL)设置充满整个圆;

接下来就是绘制这个“小球”啦。首先移动画布(改变坐标系的中心位置):在计算小球的中心位置(cx,cy)的时候,是根据大圆的半径计算的,所以这里的(cx,cy)是到大圆中心点的距离。因此,Canvas的起始位置应该移动到大圆的中心位置。

这里首先要保存一下画布,在绘制结束了还要恢复到原来的状态,为什么?因为在绘制之前我们需要对画布进行移动,当绘制结束的时候如果不恢复到原来的状态,Canvas将一直保持在目前的状态,而后面的有可能是需要在没有移动的画布上绘制其他图案,这时候的中心位置改变了,就会存在问题。

3.让小球动起来

上面的两步我们已经把静态的状态绘制完成了,但是还需要让这个小球动起来(顺着大圆环跑Y(_)Y)。其实在绘制第二步绘制小球的时候我们是固定了一个45度角,如果我们让这个角度变化(0-360),那么不就OK了。那么怎么才能做到呢?那就想啊..........,这里想到了利用ValueAimator来实现,关于这个类的使用这里就不做介绍。大家可以另外寻找相应的文章自行补脑!

AccTypeEvaluator accCore = new AccTypeEvaluator();
ValueAnimator animator = ValueAnimator.ofObject(accCore, 0.0f, 360.0f);
animator.setDuration(mDuration);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float value = (Float) animation.getAnimatedValue();
        sweepAngle = value;
        invalidate();
    }
});
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start();

这里的AccTypeEvaluator定义如下:

public class AccTypeEvaluator implements TypeEvaluator<Float>{

@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
    Log.d("", " current fraction == " + fraction);
    return fraction * (endValue - startValue);
  }
}

根据上面的代码,我们就可以获得0-360变化了,并且是随着时间的变化。当我们获取到角度时通过调用invalidate()方法,触发View重新绘制界面。这样就可以达到我们需要的动画效果啦。

总结

上面一步一步介绍了自定义UI的过程,现在应该对这个过程有所了解了——其实主要还是一个模型的建立过程。这里简单总结一下:

1.一点一点的分解UI,把复杂的界面分解成一个一个静态、简单的界面,并实现它们。

2.当静态界面绘制完了,需要动画的——观察需要改变哪些参数,并且不断的触发View绘制,不就动起来了_

3.一些比较复杂的动画或者效果就需要一些物理、数学方面的知识来辅助了——塞贝尔曲线等,其实这些就需要花费你一些时间去研究了(但是,还是那句话,从简单到复杂)。

4.多多的练习,只有练习你才能对自定义有更深的理解。

这里放一个简单的自定义UI,让大家自己实现吧(这里是静态的,大家也可以让它动起来0_0)!

练习效果

附上这个自定义UI的源码吧——github地址

如何利用ViewGroup自定义UI请阅读实践自定义UI-ViewGroup

如何利用RLF...(RelativeLayout、LinearLayout、FrameLayout...)自定义UI请阅读实践自定义UI—RLF...(RelativeLayout LinearLayout FrameLayout....)

希望在Android学习的路上,大家共同成长!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,350评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,578评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,489评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,640评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,477评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,361评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,781评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,422评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,726评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,774评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,548评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,388评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,799评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,033评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,316评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,750评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,951评论 2 336

推荐阅读更多精彩内容