一、效果图

二、设计思路

这是一个由基本图形组成的loading效果图,从图上可以看出,整个效果分为两个部分:1、三角形 2、圆环。当圆环转动一圈时,三角形并未发生变化,当圆环转动第二圈时,三角形随圆环的消失而旋转。有一定自定义View经验的朋友一定知道,我们可以用画笔画出圆、矩形、扇形等基本图形,也能通过Path(路径)来绘制三角形等任何图形。这里实现的方式有很多,我这里用了一个更为简单易懂的方法来做:

三角形:
使用Path路径绘制一个等边三角形,并将三角形绘制在最上层。
三角形旋转:
三角形的旋转我们可以通过旋转画布Canvas来实现,就不用每次都计算三角形每个点的位置了。

圆环:
使用绿色画笔绘制一个外圆,然后使用黑色画笔绘制一个内圆,内圆压在外圆上,并且内圆的半径略小于外圆的半径,这样重叠绘制之后,就能达到一个圆环的效果。但是,由于我们的动画是圆环从无到有再从有到无,所以最外层就不能直接绘制成圆形,而是绘制成一个扇形,我们通过不断改变扇形的角度,来达到圆环从无到有的动画。

圆环从有到无:
圆环绘制完一圈之后,最外圈则是绿色的外圆,内圈是黑色的内圆。那么我们只需要一个跟绿色外圆同样半径的黑色扇形来重叠在外圆上,并且通过增加黑色扇形的角度来逐渐覆盖外圈,从而实现一个看似圆环“从有到无”的效果。这时,就应该有三层,从下到上的顺序依次为:绿色外圆,黑色扇形,黑色内圆。

三、代码展示

在项目中,有三个核心的类:LoadingView(自定义控件的视图)、CircleModel(绘制圆环的类)、TriangleModel(绘制三角形的类)。LoadingView主要控制另外两个类的绘制和动画的实施。

package com.example.iqyloadingview;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;public class TriangleModel {/**三角形的三个点*/
private float pointP1X;
private float pointP1Y;
private float pointP2X;
private float pointP2Y;
private float pointP3X;
private float pointP3Y;/**中点位置*/
private float tmX;
private float tmY;private Context mContext;
/**距离边缘的距离*/
private float gap;
/**中心点到每个点的长度*/
private float cmRadius;private Path trianglePath;
private Paint trianglePaint;private int greenColor = Color.parseColor("#0BBE06");public TriangleModel(Context context, float centerWidth, float centerHeight) {mContext = context;/**初始化的时候传入三角形的中心点坐标*/tmX = centerWidth;tmY = centerHeight;initialRes();
}private void initialRes() {//gap为绘制的图形的区域离边缘的间隙gap = Utils.dpTopx(mContext, 2);//cmRdius主要作用是确定三角形的大小cmRadius = (Math.min(tmX, tmY) - gap) / 2;trianglePath = new Path();trianglePaint = new Paint();trianglePaint.setAntiAlias(true);trianglePaint.setColor(greenColor);//距中心点左上点pointP1X = tmX - cmRadius / 2;pointP1Y = (float) (tmY - Math.sin(Math.PI / 3) * cmRadius);//距中心点左下点pointP2X = pointP1X;pointP2Y = (float) (tmY + Math.sin(Math.PI / 3) * cmRadius);//距中心点右侧点pointP3X = tmX + cmRadius;pointP3Y = tmY;//路径绘制三角形区域trianglePath.moveTo(pointP1X, pointP1Y);trianglePath.lineTo(pointP2X, pointP2Y);trianglePath.lineTo(pointP3X, pointP3Y);trianglePath.close();
}/*** 绘制三角形并转动相应角度* @param canvas* @param sweepRatio 旋转比例*/
public void drawTriangle(Canvas canvas, float sweepRatio) {canvas.save();if (sweepRatio > 1)//比例大于1时,说明准备开始旋转三角形canvas.rotate(360 * (sweepRatio - 1), tmX, tmY);countPointAndDrawTriangle(canvas);canvas.restore();
}private void countPointAndDrawTriangle(Canvas canvas) {canvas.drawPath(trianglePath,trianglePaint);
}public void setPosition(float centerWidth, float centerHeight) {tmX = centerWidth;tmY = centerHeight;
}

接下来看下圆环的绘制类:

package com.example.iqyloadingview;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;public class CircleModel {
private Context mContext;//背景色为绿色的类型
public static int GREEN_TYPE = 0X001;
//背景色为黑色的类型
public static int TRANSPARENT_TYPE = 0X002;private float cmX;
private float cmY;/*** 图形离边缘的间隙*/
private float gap;private Paint mPaint;private int greenColor = Color.parseColor("#0BBE06");
private int blackColor = Color.parseColor("#000000");private RectF rectF;public CircleModel(Context context, float centerWidth, float centerHeight) {mContext = context;//圆中心点位置坐标cmX = centerWidth;cmY = centerHeight;mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setColor(greenColor);initialRes();
}private void initialRes() {gap = Utils.dpTopx(mContext, 2);rectF = new RectF(0, 0, cmX * 2, cmY * 2);}private float currentSweep;/*** 画圆环** @param canvas* @param sweepRatio 扫过的百分比 0-1*/
public void drawRing(Canvas canvas, float sweepRatio) {currentSweep = 360 * sweepRatio;//按照一定比例绘制圆环canvas.drawArc(rectF, -90, currentSweep, true, mPaint);
}public void setPaintType(int type){if(GREEN_TYPE == type){mPaint.setColor(greenColor);}else if(TRANSPARENT_TYPE == type){mPaint.setColor(blackColor);}
}public void setPosition(float centerWidth, float centerHeight) {cmX = centerWidth;cmY = centerHeight;
}/*** 设置内圆的绘制区域*/
public void setInnerRadius() {rectF.set(0+2*gap,0+2*gap,cmX * 2-2*gap, cmY * 2-2*gap);mPaint.setColor(blackColor);
}

最后则是整体控制类:

package com.example.iqyloadingview;import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;public class LoadingView extends View {
private Context mContext;
/**中心点宽度*/
private float centerWidth;
/**中心点高度*/
private float centerHeight;/**圆环相关类*/
private CircleModel circleModel;//绿色外圆
private CircleModel coverCircleModel;//黑色扇形
private CircleModel frontCircleModel;//黑色内圆
/** 三角形相关类*/
private TriangleModel triangleModel;
/**属性动画*/
private ValueAnimator valueAnimator;
private Canvas mCanvas;
/**是否需要开启动画*/
private boolean ifAnimStart = false;
/**当前的转动值*/
private float currentPoint = 0f;public LoadingView(Context context) {this(context, null);
}public LoadingView(Context context, AttributeSet attrs) {this(context, attrs, -1);
}public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;//初始化属性动画的属性值valueAnimator = ValueAnimator.ofFloat(0, 2);valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.setDuration(1800);valueAnimator.setRepeatCount(Animation.INFINITE);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {//每次获取到当前绘制比例值之后刷新视图currentPoint = (float) valueAnimator.getAnimatedValue();invalidate();}});
}@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (w != oldw) {centerWidth = w / 2;}if (h != oldh) {centerHeight = h / 2;}if (circleModel == null) {circleModel = new CircleModel(mContext, centerWidth, centerHeight);coverCircleModel = new CircleModel(mContext, centerWidth, centerHeight);frontCircleModel = new CircleModel(mContext, centerWidth, centerHeight);triangleModel = new TriangleModel(mContext, centerWidth, centerHeight);} else {//如果视图大小有所调整,则重新设置中心点circleModel.setPosition(centerWidth, centerHeight);coverCircleModel.setPosition(centerWidth, centerHeight);frontCircleModel.setPosition(centerWidth, centerHeight);triangleModel.setPosition(centerWidth, centerHeight);}}@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mCanvas == null) {mCanvas = canvas;}if(currentPoint <= 1){//0-1时绘制绿色扇形circleModel.drawRing(canvas, currentPoint);}else{//1-2时,绘制黑色扇形circleModel.drawRing(canvas, 1);coverCircleModel.setPaintType(CircleModel.TRANSPARENT_TYPE);coverCircleModel.drawRing(canvas, currentPoint-1);}frontCircleModel.setInnerRadius();frontCircleModel.drawRing(canvas, 1);//最后绘制三角形,保证三角形压在其他图形之上triangleModel.drawTriangle(canvas,currentPoint);
}/*** 开启动画*/
public void animationOpen(){if(valueAnimator != null && !valueAnimator.isRunning() && ifAnimStart == false){valueAnimator.start();ifAnimStart = true;}
}

四、总结

总体来说,这个自定义控件相对容易,需要读者掌握两个知识点:自定义View的基本方法、属性动画,这也是自定义View最基本的知识点,希望大家能从这个控件中学习到相关方法,巩固相关知识。

AndroidStudio的实例代码请点击以下链接:
http://download.csdn.net/detail/qq_30227229/9716779

Android_仿爱奇艺Loading效果相关推荐

  1. 爱奇艺首页底部导航按钮android,仿爱奇艺/腾讯视频ViewPager导航条实现

    仿爱奇艺/腾讯视频ViewPager导航条实现,支持自定义导航条高度,宽度,颜色变化,字体大小变化.支持多种滚动模式,支持自定义每个TabView的样式.项目地址:https://github.com ...

  2. 仿爱奇艺加载dialog

    仿爱奇艺在加载视频时的动画,想上张图: gif的效果有点卡,先说一下实现的方法, 主要的难点在于怎样将三角形画到空间的中间,我通过三角形中心到顶角的距离来确定三角形的大小, 当三角形在中间时角a的大小 ...

  3. 仿爱奇艺视频,腾讯视频,搜狐视频首页推荐位轮播图(二)之SuperIndicator源码分析

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52510431 背景:仿爱奇艺视频,腾讯视频 ...

  4. html实现视频网站,仿爱奇艺,搜狐,迅雷看看(附源码)

    文章目录 1.功能模板 1.1 仿爱奇艺 1.2 仿搜狐视频 1.3 仿迅雷看看 1.4 视频播放 1.5 影视公司官网 2.效果和源码 2.1 源代码 2.2 模板目录 源码下载 作者:xcLeig ...

  5. android高仿奇艺影视,android仿爱奇艺加载动画实例

    本篇文章介绍了android仿爱奇艺加载动画实例,具体代码如下: 效果图: 用到的知识点: Path ValueAnimator 如果对Path和ValueAnimator还不熟悉推荐去看这几个大神的 ...

  6. Android基础控件——TabLayout的使用、仿爱奇艺导航条

    TabLayout的使用.仿爱奇艺导航条 学习,学习,学以致用,让基础控件贴近实战效果 TabLayout是Google新推出的Material Design的控件之一,TabLayout的使用必须结 ...

  7. 仿爱奇艺UI界面(第一天)

    仿爱奇艺UI界面 1.整体布局 是一个Activity,再一个Activity界面中填充不同的Fragment. 主界面是一个LinearLayout布局,在布局中放一个FrameLayout用来做显 ...

  8. 苹果cms v8模板 高仿爱奇艺带PC+手机模板

    介绍: 苹果cms v8模板 高仿爱奇艺带PC+手机模板 网盘下载地址: http://kekewl.net/frgNDYcaQne0 图片:

  9. 仿爱奇艺视频,腾讯视频,搜狐视频首页推荐位轮播图介绍(一)

    请尊重分享成果,转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52327435 前言:本篇只是一个介绍这个一个类库,具体实现思路代码会下 ...

最新文章

  1. python导入哨兵数据_Python 下载哨兵Sentinel数据(Sentinel-1~3)
  2. linux ubi 分区,Linux最新UBI文件系统介绍
  3. Kafka分区分配策略(1)——RangeAssignor
  4. sybase自增与插入
  5. 前端架构gulp与webpack(知识点整理)
  6. Selector#wakeup()
  7. php学习笔记0001 变量作用域
  8. php.h not found,编译错误“fatal error: 'xxxx.h' file not found” 如何解决
  9. 如何编写银行转账的测试用例,可以来看这里.....
  10. DICOM获取worklist患者列表抓包分析
  11. 【Multisim仿真】数字电路仿真16路往复流水灯
  12. java 日历选择天_如何从Java中的日历对象构建天,月,年的列表?
  13. 操作系统进程同步之吸烟者问题,C语言实现
  14. 电子电路基础 (14)——稳压电源的工作原理分析
  15. 整理wind商誉数据2016-2019
  16. Java Simon--性能瓶颈分析工具
  17. 网易的315页面碉堡了,速围观
  18. 电磁场与电磁波:法拉第电磁感应定律,高斯定律的高斯定律
  19. 数据趣事之父亲节专辑
  20. 用vb.net开发的简易(通用)上位机

热门文章

  1. Win7网络修复,winsock/tcpip
  2. Java技术进阶推荐书单
  3. 题目1:MySQL基本练习【单、多表】
  4. 学ps要计算机基础吗,零基础怎样学会PS?电脑0零基础绘画
  5. 手把手教你用Python打造一个语音合成系统(已生成软件)
  6. java 别名现象_引用与对象赋值时的别名现象
  7. iOS内测分发平台的选择与标准
  8. 怎样促进计算机专业发展,【计算机教学论文】怎样促进计算机技术应用及改善(共4879字)...
  9. Photoshop:使用层遮照制作图像渐变特效(2)
  10. grpc加TLS加密和令牌认证