前言
一般在APP没有网络的情况下,我们都会用一个无网络的提示图标,在提示方面为了统一app的情况,我们一般使用简单的提示图标,偶尔只需要改变一下图标的颜色就一举两得,而不需要让PS来换一次颜色。当然app有图标特殊要求的就另当别论了。
效果图
当你第一眼看到这样的图,二话不说直接让UI给你切一张图标来的快对吧,我其实开始也是这么想的,但是到了做的app越来越多的时候,你就会发现就算是用这个简单的图标,随着主题颜色的改变,我们的图标颜色也会发生相应的改变,我们需要的就随意改变这个图标颜色,那么改变图标颜色就难了,还是自己着手自己写一个控件吧,看着这个控件我有点愣住了,因为有平滑效果,怎么弄呢。我问了一下UI他们怎么绘制的,结果他给我说这个图标他们是用圆来完成的。从中得到启发的我,开始着手来完成这样一个控件。
控件分析
使用
(1)将下面的源码复制到自己项目中,本人不提倡用Git依赖,依赖多了打包慢,写代码卡。
(2)以下是可以用到的方法
/**
* 设置扇形高度
*
* @param arcStrokeWidth
*/
public void setStrokeWidth(float arcStrokeWidth)
/**
* 设置扇形的半径
*
* @param radius
*/
public void setRadius(float radius)
/**
* 设置扇形的间距
*
* @param arcPadding
*/
public void setArcPadding(float arcPadding)
/**
* 设置扇形数量
*
* @param arcCount
*/
public void setArcCount(int arcCount)
/**
* 设置开始角度
*
* @param startAngle
*/
public void setStartAngle(float startAngle)
/**
* 设置颜色
*
* @param color
*/
public void setColor(int color)
/**
* 设置动画时间
*
* @param duration
*/
public void setDuration(int duration)
/**
* 开始动画
*/
public void startAnimation()
/**
* 停止动画
*/
public void stopAnimation()
布局xml
<com.android.widget.ArcNetView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:arc_color="@color/colorAccent"
app:arc_animation="true"/>
注:包名请修改成自己项目的包名(ArcNetView复制到自己项目中);
attr.xml
<declare-styleable name="ArcNetView">
<attr name="arc_count" format="integer" />
<attr name="arc_color" format="color" />
<attr name="arc_radius" format="dimension" />
<attr name="arc_stroke_width" format="dimension" />
<attr name="arc_padding" format="dimension" />
<attr name="arc_animation" format="boolean" />
ArcNetView
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
import com.android.R;
/**
* Created by Relin
* on 2018-09-11.
* 扇形网络控件
*/
public class ArcNetView extends View {
private Canvas canvas;
private Paint paint;
private float arcStrokeWidth = dpToPx(24);
private float radius = dpToPx(28);
private float arcPadding = dpToPx(20);
private int arcCount = 3;
private float width;
private float height;
private float startAngle = -135;
private float sweepAngle = Math.abs(startAngle + 90) * 2;
private float circleY;
private float circleX;
private ValueAnimator animator;
private boolean isStart;
private int duration = 600;
private int arcColor = Color.parseColor("#005F91");
public ArcNetView(Context context) {
super(context);
init(context, null);
}
public ArcNetView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ArcNetView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
/**
* 初始化
*
* @param context
* @param attrs
*/
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.NetworkView);
arcCount = array.getColor(R.styleable.NetworkView_arc_count, arcCount);
arcColor = array.getColor(R.styleable.NetworkView_arc_color, arcColor);
radius = array.getDimension(R.styleable.NetworkView_arc_radius, radius);
arcStrokeWidth = array.getDimension(R.styleable.NetworkView_arc_stroke_width, arcStrokeWidth);
arcPadding = array.getDimension(R.styleable.NetworkView_arc_padding, arcPadding);
isStart = array.getBoolean(R.styleable.NetworkView_arc_animation, isStart);
array.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int w = widthSpecSize;
int h = heightSpecSize;
int needHeight = (int) (radius * arcCount + arcStrokeWidth / 2 + arcPadding * arcCount);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
w = needHeight;
h = needHeight;
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
w = needHeight;
h = heightSpecSize;
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
w = widthSpecSize;
h = needHeight;
}
setMeasuredDimension(w, h);
//获取最终的宽高
width = getMeasuredWidth();
height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
radius -= getPaddingLeft() - getPaddingRight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
//初始化画笔
paint = new Paint();
paint.setColor(arcColor);
paint.setStrokeWidth(arcStrokeWidth);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
circleX = width / 2;
circleY = height / 2 + radius * arcCount / 2 + arcStrokeWidth / (arcCount * 2);
//类型绘制
if (!isStart) {
for (int i = 0; i < arcCount; i++) {
drawArcView(canvas, i);
}
//绘制最底部圆
drawCircle(canvas, arcColor, circleX, circleY, arcStrokeWidth / 2);
} else {
animationDraw();
}
}
/**
* 动态绘制
*/
private void animationDraw() {
animator = ValueAnimator.ofInt(-1, arcCount + 1);// -1 0 1 2 3
animator.setDuration(duration);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(-1);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
if (value == arcCount) {
canvas.restore();
}
if (value == -1 || value == arcCount) {
drawCircle(canvas, arcColor, circleX, circleY, arcStrokeWidth / 2);
}
if (value > -1) {
drawArcView(canvas, value);
}
invalidate();
Log.e("RRL", "value:" + value);
}
});
animator.start();
}
/**
* 绘制上部分
*
* @param canvas 画布
* @param acrIndex 绘制下标[第几个扇形]
*/
private void drawArcView(Canvas canvas, int acrIndex) {
//绘制扇形
float arcRadius = radius + (arcStrokeWidth / 2 + arcPadding) * acrIndex;
RectF rectF = new RectF(circleX - arcRadius, circleY - arcRadius, circleX + arcRadius, circleY + arcRadius);
canvas.drawArc(rectF, startAngle, sweepAngle, false, paint);
//绘制两端圆点
double angle = (sweepAngle / 2) * Math.PI / 180;
float x = (float) (Math.sin(angle) * arcRadius);
float y = (float) (Math.cos(angle) * arcRadius);
//左边圆点
drawCircle(canvas, arcColor, circleX - x, circleY - y, arcStrokeWidth / 2);
//右边圆点
drawCircle(canvas, arcColor, circleX + x, circleY - y, arcStrokeWidth / 2);
}
/**
* 绘制圆
*
* @param canvas 画布
* @param color 颜色
* @param circleX 圆中心X
* @param circleY 圆中心Y
* @param radius 圆半径
*/
public void drawCircle(Canvas canvas, int color, float circleX, float circleY, float radius) {
Paint circlePaint = new Paint();
circlePaint.setColor(color);
circlePaint.setStyle(Paint.Style.FILL);
circlePaint.setAntiAlias(true);
canvas.drawCircle(circleX, circleY, radius, circlePaint);
}
public static float dpToPx(float dp) {
return dp * getScreenDensity();
}
public static float getScreenDensity() {
return Resources.getSystem().getDisplayMetrics().density;
}
/**
* 设置扇形高度
*
* @param arcStrokeWidth
*/
public void setStrokeWidth(float arcStrokeWidth) {
this.arcStrokeWidth = dpToPx(arcStrokeWidth);
}
/**
* 设置扇形的半径
*
* @param radius
*/
public void setRadius(float radius) {
this.radius = dpToPx(radius);
}
/**
* 设置扇形的间距
*
* @param arcPadding
*/
public void setArcPadding(float arcPadding) {
this.arcPadding = dpToPx(arcPadding);
}
/**
* 设置扇形数量
*
* @param arcCount
*/
public void setArcCount(int arcCount) {
this.arcCount = arcCount;
}
/**
* 设置开始角度
*
* @param startAngle
*/
public void setStartAngle(float startAngle) {
this.startAngle = startAngle;
this.sweepAngle = Math.abs(startAngle + 90) * 2;
}
/**
* 设置颜色
*
* @param color
*/
public void setColor(int color) {
this.arcColor = color;
}
/**
* 设置动画时间
*
* @param duration
*/
public void setDuration(int duration) {
this.duration = duration;
}
/**
* 开始动画
*/
public void startAnimation() {
isStart = true;
invalidate();
}
/**
* 停止动画
*/
public void stopAnimation() {
isStart = false;
if (animator != null) {
animator.removeAllUpdateListeners();
animator = null;
}
invalidate();
}
}