1.自定义
/**
* 旋转加载动画控件
*/
public class RotateLoadingView extends View {
/**
* 默认圆弧的宽度
*/
private static final int DEFAULT_ARC_WIDTH = 6;
/**
* 默认旋转度数的速度
*/
private static final int DEFAULT_SPEED_OF_DEGREE = 5;
/**
* 是否需要画图
*/
private boolean mIsDraw;
/**
* 是否是自动模式,无需人工干预
*/
private boolean mIsAutoMode = true;
/**
* 圆弧画笔
*/
private Paint mArcPaint;
/**
* 圆弧画笔的粗细
*/
private int mArcWidth;
/**
* 圆弧的颜色
*/
private int mArcColor;
/**
* 背景圆弧颜色
*/
private int mbgArcColor;
private boolean mIsSingleArc;
/**
* 圆弧所在的椭圆对象
*/
private RectF mLoadingRectF;
/**
* 上弧的度数
*/
private int mTopDegree = 10;
/**
* 下弧的度数
*/
private int mBottomDegree = 190;
/**
* 圆弧的角度
*/
private float mArcDegree;
/**
* 圆弧的最大角度
*/
private int mMaxArcDegree;
/**
* 上下弧度数的变化速度
*/
private int mSpeedOfDegree;
/**
* 圆弧角度的变化速度
*/
private float mSpeedOfArc;
/**
* 圆弧是否开始变大
*/
private boolean mChangeBigger = true;
/**
* 图标
*/
private Bitmap mIconBitmap;
/**
* 图标缩放比例
*/
private float mIconScale;
/**
* 绘制图标的画笔
*/
private Paint mIconPaint;
/**
* 背景画笔
*/
private Paint mBackPaint;
private int mWidth;
private int mHeight;
private float mStrokeWidth = 50;
private float mRadius = 50;
public RotateLoadingView(Context context) {
super(context);
initAttrs(context, null);
}
public RotateLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
initAttrs(context, attrs);
}
public RotateLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);
mArcColor = typedArray.getColor(R.styleable.LoadingView_lv_color, ThemeUtils.getMainThemeColor(context));
mbgArcColor=typedArray.getColor(R.styleable.LoadingView_lv_bg_color, ThemeUtils.getMainThemeColor(context));
mArcWidth = typedArray.getDimensionPixelSize(R.styleable.LoadingView_lv_width, DensityUtils.dp2px(getContext(), DEFAULT_ARC_WIDTH));
mSpeedOfDegree = typedArray.getInt(R.styleable.LoadingView_lv_speed, DEFAULT_SPEED_OF_DEGREE);
mSpeedOfArc = mSpeedOfDegree >> 2;
mIsDraw = mIsAutoMode = typedArray.getBoolean(R.styleable.LoadingView_lv_auto, true);
mIsSingleArc = typedArray.getBoolean(R.styleable.LoadingView_lv_arc_single, false);
mMaxArcDegree = mIsSingleArc ? 280 : 160;
boolean hasIcon = typedArray.getBoolean(R.styleable.LoadingView_lv_has_icon, true);
if (hasIcon) {
Drawable icon = ResUtils.getDrawableAttrRes(getContext(), typedArray, R.styleable.LoadingView_lv_icon);
if (icon != null) {
mIconBitmap = Utils.getBitmapFromDrawable(icon);
} else {
Drawable appIcon = Utils.getAppIcon(getContext());
if (appIcon != null) {
mIconBitmap = Utils.getBitmapFromDrawable(appIcon);
}
}
mIconScale = typedArray.getFloat(R.styleable.LoadingView_lv_icon_scale, 0.5F);
}
typedArray.recycle();
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
mBackPaint = new Paint();
mBackPaint.setColor(mbgArcColor);
mBackPaint.setAntiAlias(true);
mBackPaint.setStyle(Paint.Style.STROKE);
mBackPaint.setStrokeWidth(mArcWidth);
mBackPaint.setStrokeCap(Paint.Cap.ROUND);
mArcPaint = new Paint();
mArcPaint.setColor(mArcColor);
mArcPaint.setAntiAlias(true);
mArcPaint.setStyle(Paint.Style.STROKE);
mArcPaint.setStrokeWidth(mArcWidth);
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mIconPaint = new Paint();
mIconPaint.setColor(mArcColor);
mIconPaint.setAntiAlias(true);
mIconPaint.setStyle(Paint.Style.STROKE);
mIconPaint.setStrokeCap(Paint.Cap.ROUND);
}
//重写测量大小的onMeasure方法和绘制View的核心方法onDraw()
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getRealSize(widthMeasureSpec);
mHeight = getRealSize(heightMeasureSpec);
setMeasuredDimension(mWidth, mHeight);
}
public int getRealSize(int measureSpec) {
int result = 1;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED) {
//自己计算
result = (int) (mRadius * 2 + mStrokeWidth);
} else {
result = size;
}
return result;
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
mArcDegree = 10;
mLoadingRectF = new RectF(mArcWidth, mArcWidth, width - mArcWidth, height - mArcWidth);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!mIsDraw) {
return;
}
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius, mBackPaint);
drawArc(canvas);
changeArcDegree();
invalidate();
}
/**
* 画圆弧
*
* @param canvas
*/
private void drawArc(Canvas canvas) {
if (mIconBitmap != null) {
canvas.drawBitmap(mIconBitmap, null, getIconBitmapRectF(mIconBitmap), mIconPaint);
}
drawTopArc(canvas);
if (!mIsSingleArc) {
drawBottomArc(canvas);
}
}
/**
* 画上弧
*
* @param canvas
*/
private void drawTopArc(Canvas canvas) {
canvas.drawArc(mLoadingRectF, mTopDegree, mArcDegree, false, mArcPaint);
mTopDegree += mSpeedOfDegree;
if (mTopDegree > 360) {
mTopDegree = mTopDegree - 360;
}
}
/**
* 画下弧
*
* @param canvas
*/
private void drawBottomArc(Canvas canvas) {
canvas.drawArc(mLoadingRectF, mBottomDegree, mArcDegree, false, mArcPaint);
mBottomDegree += mSpeedOfDegree;
if (mBottomDegree > 360) {
mBottomDegree = mBottomDegree - 360;
}
}
/**
* 改变圆弧的角度
*/
private void changeArcDegree() {
if (mChangeBigger) {
if (mArcDegree < mMaxArcDegree) {
mArcDegree += mSpeedOfArc;
}
} else {
if (mArcDegree > mSpeedOfDegree) {
mArcDegree -= 2 * mSpeedOfArc;
}
}
if (mArcDegree >= mMaxArcDegree || mArcDegree <= mSpeedOfDegree) {
mChangeBigger = !mChangeBigger;
}
}
/**
* 获取中心图标所在的区域
*
* @return
*/
public RectF getIconBitmapRectF(Bitmap bitmap) {
float width = bitmap.getWidth(), height = bitmap.getHeight();
if (width >= height) {
height = getWidth() / width * height;
width = getWidth();
} else {
width = getHeight() / height * width;
height = getHeight();
}
float left = (getWidth() - width * mIconScale) / 2;
float top = (getHeight() - height * mIconScale) / 2;
float right = getWidth() - left;
float bottom = getHeight() - top;
return new RectF(left, top, right, bottom);
}
/**
* 设置loading的图标
*
* @param icon
* @return
*/
public RotateLoadingView setLoadingIcon(Drawable icon) {
if (icon != null) {
mIconBitmap = Utils.getBitmapFromDrawable(icon);
}
return this;
}
/**
* 设置loading的图标
*
* @param iconBitmap
* @return
*/
public RotateLoadingView setLoadingIcon(Bitmap iconBitmap) {
mIconBitmap = iconBitmap;
return this;
}
public RotateLoadingView setLoadingColor(int color) {
mArcColor = color;
return this;
}
public int getLoadingColor() {
return mArcColor;
}
/**
* 开始旋转
*/
public void start() {
if (!mIsAutoMode) {
mIsDraw = true;
invalidate();
}
}
/**
* 停止旋转
*/
public void stop() {
if (!mIsAutoMode) {
pause();
}
}
/**
* 暂停旋转并消失
*/
private void pause() {
mIsDraw = false;
invalidate();
}
public boolean isStart() {
return mIsDraw;
}
/**
* 资源释放
*/
public void recycle() {
pause();
if (mIconBitmap != null) {
mIconBitmap.recycle();
mIconBitmap = null;
}
mBackPaint=null;
mArcPaint = null;
mIconPaint = null;
mLoadingRectF = null;
}
}
public class Utils {
/**
* 将Drawable转化为Bitmap
*
* @param drawable Drawable
* @return Bitmap
*/
public static Bitmap getBitmapFromDrawable(Drawable drawable) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, drawable
.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);
return bitmap;
}
/**
* 获取应用的图标
*
* @param context
* @return
*/
public static Drawable getAppIcon(Context context) {
try {
PackageManager pm = context.getPackageManager();
ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0);
return info.loadIcon(pm);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
themeUtils.java
/**
* 获取主题色
*
* @param context 上下文
* @return 主题色
*/
@ColorInt
public static int getMainThemeColor(Context context) {
return resolveColor(context, R.attr.colorAccent, getColor(context, R.color.xui_config_color_main_theme));
}
@ColorInt
public static int resolveColor(Context context, @AttrRes int attr) {
return resolveColor(context, attr, 0);
}
@ColorInt
public static int resolveColor(Context context, @AttrRes int attr, int fallback) {
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr});
try {
return a.getColor(0, fallback);
} finally {
a.recycle();
}
}
使用:
- <RotateLoadingView
android:id="@+id/loading"
android:layout_width="26dp"
android:layout_height="26dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lv_arc_single="true"
app:lv_speed="8"
app:lv_width="2dp"
app:lv_color="#FFFFFF"
app:lv_bg_color="#33FFFFFF"
app:lv_auto="true"
app:lv_has_icon="false" />
attr.xml
<!--LoadingView-->
<declare-styleable name="LoadingView">
<!--loading加载画笔的粗细-->
<attr name="lv_width" format="dimension" />
<!--loading加载画笔的颜色-->
<attr name="lv_color" format="color" />
<!--loading背景颜色-->
<attr name="lv_bg_color" format="color" />
<!--loading加载旋转的速度-->
<attr name="lv_speed" format="integer" />
<!--是否有loading中心的图标, 默认是true-->
<attr name="lv_has_icon" format="boolean" />
<!--loading中心的图标-->
<attr name="lv_icon" format="reference" />
<!--loading中心图标缩放的比例, 默认是0.5-->
<attr name="lv_icon_scale" format="float" />
<!--圆弧的角度-->
<attr name="lv_arc_degree" format="integer" />
<!--是否自动旋转,无需人工控制,默认是true-->
<attr name="lv_auto" format="boolean" />
<!--是否单弧旋转,默认false-->
<attr name="lv_arc_single" format="boolean" />
</declare-styleable>
2.ProgressBar
<ProgressBar
android:id="@+id/arc_loading"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginLeft="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:indeterminateDrawable="@drawable/bar" />
1.bar.xml 自己填充颜色
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360">
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="10"
android:useLevel="false">
<gradient
android:centerY="0.5"
android:endColor="#FFFFFF" //结束的颜色
android:startColor="#10FFFFFF" //开始的颜色
android:type="sweep"
android:useLevel="false" />
</shape>
</animated-rotate>
2、设置图片
一 首相在drawable文件夹中建立如下旋转动画文件
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/loading1"
android:pivotX="50%"
android:pivotY="50%" />
其中loading1即为您想用的图片
二 在布局文件中设置progressbar
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/progressbg"
android:indeterminateOnly="true"
android:indeterminateBehavior="repeat"
/>
参考:android画笔,Android自定义View系列之画笔(一)_Gaosaroma的博客-CSDN博客
Android编程之ProgressBar圆形进度条颜色设置方法 / 张生荣
XUI