看企业网站怎么做到百度秒收,昆山周市建设局网站,seo快速排名软件网址,珠海网站制作定制最终效果如下 从效果上看#xff0c;我们需要考虑以下几个问题#xff1a; 1.叶子的随机产生#xff1b; 2.叶子随着一条正余弦曲线移动#xff1b; 3.叶子在移动的时候旋转#xff0c;旋转方向随机#xff0c;正时针或逆时针#xff1b; 4.叶子遇到进度条#xff…最终效果如下 从效果上看我们需要考虑以下几个问题 1.叶子的随机产生 2.叶子随着一条正余弦曲线移动 3.叶子在移动的时候旋转旋转方向随机正时针或逆时针 4.叶子遇到进度条似乎是融合进入 5.叶子不能超出最左边的弧角 7.叶子飘出时的角度不是一致走的曲线的振幅也有差别否则太有规律性缺乏美感
总的看起来需要注意和麻烦的地方主要是以上几点当然还有一些细节问题比如最左边是圆弧等等 那接下来我们将效果进行分解然后逐个击破 整个效果来说我们需要的图主要是飞动的小叶子和右边旋转的风扇其他的部分都可以用色值进行绘制当然我们为了方便就连底部框一起切了 先从gif 图里把飞动的小叶子和右边旋转的风扇、底部框抠出来小叶子图如下 我们需要处理的主要有两个部分 1. 随着进度往前绘制的进度条 2. 不断飞出来的小叶片
我们先处理第一部分 随着进度往前绘制的进度条 进度条的位置根据外层传入的 progress 进行计算可以分为图中 1、2、3 三个阶段 当progress 较小算出的当前距离还在弧形以内时需要绘制如图所示 1 区域的弧形其余部分用白色填充 当 progress 算出的距离到2时需要绘制棕色半圆弧形其余部分用白色矩形填充 当 progress 算出的距离到3 时需要绘制棕色半圆弧形棕色矩形白色矩形 当 progress 算出的距离到头时需要绘制棕色半圆弧形棕色矩形可以合并到3中
首先根据进度条的宽度和当前进度、总进度算出当前的位置
//mProgressWidth为进度条的宽度根据当前进度算出进度条的位置
mCurrentProgressPosition mProgressWidth * mProgress / TOTAL_PROGRESS;
然后按照上面的逻辑进行绘制其中需要计算上图中的红色弧角角度计算方法如下
// 单边角度
int angle (int) Math.toDegrees(Math.acos((mArcRadius - mCurrentProgressPosition)/ (float) mArcRadius));
Math.acos() 反余弦函数 Math.toDegrees() 弧度转化为角度Math.toRadians 角度转化为弧度
所以圆弧的起始点为
int startAngle 180 - angle;
圆弧划过的角度为2 * angle
这一块的代码如下
// mProgressWidth为进度条的宽度根据当前进度算出进度条的位置
mCurrentProgressPosition mProgressWidth * mProgress / TOTAL_PROGRESS;
// 即当前位置在图中所示1范围内
if (mCurrentProgressPosition mArcRadius) { Log.i(TAG, mProgress mProgress ---mCurrentProgressPosition mCurrentProgressPosition --mArcProgressWidth mArcRadius); // 1.绘制白色ARC绘制orange ARC // 2.绘制白色矩形 // 1.绘制白色ARC canvas.drawArc(mArcRectF, 90, 180, false, mWhitePaint); // 2.绘制白色矩形 mWhiteRectF.left mArcRightLocation; canvas.drawRect(mWhiteRectF, mWhitePaint); // 3.绘制棕色 ARC // 单边角度 int angle (int) Math.toDegrees(Math.acos((mArcRadius - mCurrentProgressPosition) / (float) mArcRadius)); // 起始的位置 int startAngle 180 - angle; // 扫过的角度 int sweepAngle 2 * angle; Log.i(TAG, startAngle startAngle); canvas.drawArc(mArcRectF, startAngle, sweepAngle, false, mOrangePaint);
} else { Log.i(TAG, mProgress mProgress ---transfer-----mCurrentProgressPosition mCurrentProgressPosition --mArcProgressWidth mArcRadius); // 1.绘制white RECT // 2.绘制Orange ARC // 3.绘制orange RECT // 1.绘制white RECT mWhiteRectF.left mCurrentProgressPosition; canvas.drawRect(mWhiteRectF, mWhitePaint); // 2.绘制Orange ARC canvas.drawArc(mArcRectF, 90, 180, false, mOrangePaint); // 3.绘制orange RECT mOrangeRectF.left mArcRightLocation; mOrangeRectF.right mCurrentProgressPosition; canvas.drawRect(mOrangeRectF, mOrangePaint); }
叶子部分
首先根据效果情况基本确定出 曲线函数标准函数方程为y A(wxQ)h其中w影响周期A影响振幅 周期T 2 * Math.PI/w; 根据效果可以看出周期大致为总进度长度所以确定w(float) ((float) 2 * Math.PI /mProgressWidth)
仔细观察效果我们可以发现叶子飘动的过程中振幅不是完全一致的产生一种错落的效果既然如此我们给叶子定义一个Type根据Type 确定不同的振幅
我们创建一个叶子对象
private class Leaf { // 在绘制部分的位置 float x, y; // 控制叶子飘动的幅度 StartType type; // 旋转角度 int rotateAngle; // 旋转方向--0代表顺时针1代表逆时针 int rotateDirection; // 起始时间(ms) long startTime; }
类型采用枚举进行定义其实就是用来区分不同的振幅
private enum StartType { LITTLE, MIDDLE, BIG
}
创建一个LeafFactory类用于创建一个或多个叶子信息
private class LeafFactory { private static final int MAX_LEAFS 6; Random random new Random(); // 生成一个叶子信息 public Leaf generateLeaf() { Leaf leaf new Leaf(); int randomType random.nextInt(3); // 随时类型 随机振幅 StartType type StartType.MIDDLE; switch (randomType) { case 0: break; case 1: type StartType.LITTLE; break; case 2: type StartType.BIG; break; default: break; } leaf.type type; // 随机起始的旋转角度 leaf.rotateAngle random.nextInt(360); // 随机旋转方向顺时针或逆时针 leaf.rotateDirection random.nextInt(2); // 为了产生交错的感觉让开始的时间有一定的随机性 mAddTime random.nextInt((int) (LEAF_FLOAT_TIME * 1.5)); leaf.startTime System.currentTimeMillis() mAddTime; return leaf; } // 根据最大叶子数产生叶子信息 public ListLeaf generateLeafs() { return generateLeafs(MAX_LEAFS); } // 根据传入的叶子数量产生叶子信息 public ListLeaf generateLeafs(int leafSize) { ListLeaf leafs new LinkedListLeaf(); for (int i 0; i leafSize; i) { leafs.add(generateLeaf()); } return leafs; }
定义两个常亮分别记录中等振幅和之间的振幅差
// 中等振幅大小
private static final int MIDDLE_AMPLITUDE 13;
// 不同类型之间的振幅差距
private static final int AMPLITUDE_DISPARITY 5;
// 中等振幅大小
private int mMiddleAmplitude MIDDLE_AMPLITUDE;
// 振幅差
private int mAmplitudeDisparity AMPLITUDE_DISPARITY;
有了以上信息我们则可以获取到叶子的Y值
// 通过叶子信息获取当前叶子的Y值
private int getLocationY(Leaf leaf) { // y A(wxQ)h float w (float) ((float) 2 * Math.PI / mProgressWidth); float a mMiddleAmplitude; switch (leaf.type) { case LITTLE: // 小振幅 中等振幅 振幅差 a mMiddleAmplitude - mAmplitudeDisparity; break; case MIDDLE: a mMiddleAmplitude; break; case BIG: // 小振幅 中等振幅 振幅差 a mMiddleAmplitude mAmplitudeDisparity; break; default: break; } Log.i(TAG, ---a a ---w w --leaf.x leaf.x); return (int) (a * Math.sin(w * leaf.x)) mArcRadius * 2 / 3;
}
绘制叶子
/** * 绘制叶子 * * param canvas */
private void drawLeafs(Canvas canvas) { long currentTime System.currentTimeMillis(); for (int i 0; i mLeafInfos.size(); i) { Leaf leaf mLeafInfos.get(i); if (currentTime leaf.startTime leaf.startTime ! 0) { // 绘制叶子根据叶子的类型和当前时间得出叶子的xy getLeafLocation(leaf, currentTime); // 根据时间计算旋转角度 canvas.save(); // 通过Matrix控制叶子旋转 Matrix matrix new Matrix(); float transX mLeftMargin leaf.x; float transY mLeftMargin leaf.y; Log.i(TAG, left.x leaf.x --leaf.y leaf.y); matrix.postTranslate(transX, transY); // 通过时间关联旋转角度则可以直接通过修改LEAF_ROTATE_TIME调节叶子旋转快慢 float rotateFraction ((currentTime - leaf.startTime) % LEAF_ROTATE_TIME) / (float) LEAF_ROTATE_TIME; int angle (int) (rotateFraction * 360); // 根据叶子旋转方向确定叶子旋转角度 int rotate leaf.rotateDirection 0 ? angle leaf.rotateAngle : -angle leaf.rotateAngle; matrix.postRotate(rotate, transX mLeafWidth / 2, transY mLeafHeight / 2); canvas.drawBitmap(mLeafBitmap, matrix, mBitmapPaint); canvas.restore(); } else { continue; } }
}
LeafLoadingView完整代码 package com.example.csdnblog4;import java.util.LinkedList;
import java.util.List;
import java.util.Random;import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;public class LeafLoadingView extends View {private static final String TAG LeafLoadingView;// 淡白色private static final int WHITE_COLOR 0xfffde399;// 橙色private static final int ORANGE_COLOR 0xffffa800;// 中等振幅大小private static final int MIDDLE_AMPLITUDE 13;// 不同类型之间的振幅差距private static final int AMPLITUDE_DISPARITY 5;// 总进度private static final int TOTAL_PROGRESS 100;// 叶子飘动一个周期所花的时间private static final long LEAF_FLOAT_TIME 3000;// 叶子旋转一周需要的时间private static final long LEAF_ROTATE_TIME 2000;// 用于控制绘制的进度条距离左上下的距离private static final int LEFT_MARGIN 9;// 用于控制绘制的进度条距离右的距离private static final int RIGHT_MARGIN 25;private int mLeftMargin, mRightMargin;// 中等振幅大小private int mMiddleAmplitude MIDDLE_AMPLITUDE;// 振幅差private int mAmplitudeDisparity AMPLITUDE_DISPARITY;// 叶子飘动一个周期所花的时间private long mLeafFloatTime LEAF_FLOAT_TIME;// 叶子旋转一周需要的时间private long mLeafRotateTime LEAF_ROTATE_TIME;private Resources mResources;private Bitmap mLeafBitmap;private int mLeafWidth, mLeafHeight;private Bitmap mOuterBitmap;private Rect mOuterSrcRect, mOuterDestRect;private int mOuterWidth, mOuterHeight;private int mTotalWidth, mTotalHeight;private Paint mBitmapPaint, mWhitePaint, mOrangePaint;private RectF mWhiteRectF, mOrangeRectF, mArcRectF;// 当前进度private int mProgress;// 所绘制的进度条部分的宽度private int mProgressWidth;// 当前所在的绘制的进度条的位置private int mCurrentProgressPosition;// 弧形的半径private int mArcRadius;// arc的右上角的x坐标也是矩形x坐标的起始点private int mArcRightLocation;// 用于产生叶子信息private LeafFactory mLeafFactory;// 产生出的叶子信息private ListLeaf mLeafInfos;// 用于控制随机增加的时间不抱团private int mAddTime;public LeafLoadingView(Context context, AttributeSet attrs) {super(context, attrs);mResources getResources();mLeftMargin UiUtils.dipToPx(context, LEFT_MARGIN);mRightMargin UiUtils.dipToPx(context, RIGHT_MARGIN);mLeafFloatTime LEAF_FLOAT_TIME;mLeafRotateTime LEAF_ROTATE_TIME;initBitmap();initPaint();mLeafFactory new LeafFactory();mLeafInfos mLeafFactory.generateLeafs();}private void initPaint() {mBitmapPaint new Paint();mBitmapPaint.setAntiAlias(true);mBitmapPaint.setDither(true);mBitmapPaint.setFilterBitmap(true);mWhitePaint new Paint();mWhitePaint.setAntiAlias(true);mWhitePaint.setColor(WHITE_COLOR);mOrangePaint new Paint();mOrangePaint.setAntiAlias(true);mOrangePaint.setColor(ORANGE_COLOR);}Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 绘制进度条和叶子// 之所以把叶子放在进度条里绘制主要是层级原因drawProgressAndLeafs(canvas);// drawLeafs(canvas);canvas.drawBitmap(mOuterBitmap, mOuterSrcRect, mOuterDestRect, mBitmapPaint);postInvalidate();}private void drawProgressAndLeafs(Canvas canvas) {if (mProgress TOTAL_PROGRESS) {mProgress 0;}// mProgressWidth为进度条的宽度根据当前进度算出进度条的位置mCurrentProgressPosition mProgressWidth * mProgress / TOTAL_PROGRESS;// 即当前位置在图中所示1范围内if (mCurrentProgressPosition mArcRadius) {Log.i(TAG, mProgress mProgress ---mCurrentProgressPosition mCurrentProgressPosition --mArcProgressWidth mArcRadius);// 1.绘制白色ARC绘制orange ARC// 2.绘制白色矩形// 1.绘制白色ARCcanvas.drawArc(mArcRectF, 90, 180, false, mWhitePaint);// 2.绘制白色矩形mWhiteRectF.left mArcRightLocation;canvas.drawRect(mWhiteRectF, mWhitePaint);// 绘制叶子drawLeafs(canvas);// 3.绘制棕色 ARC// 单边角度int angle (int) Math.toDegrees(Math.acos((mArcRadius - mCurrentProgressPosition)/ (float) mArcRadius));// 起始的位置int startAngle 180 - angle;// 扫过的角度int sweepAngle 2 * angle;canvas.drawArc(mArcRectF, startAngle, sweepAngle, false, mOrangePaint);} else {Log.i(TAG, mProgress mProgress ---transfer-----mCurrentProgressPosition mCurrentProgressPosition --mArcProgressWidth mArcRadius);// 1.绘制white RECT// 2.绘制Orange ARC// 3.绘制orange RECT// 这个层级进行绘制能让叶子感觉是融入棕色进度条中// 1.绘制white RECTmWhiteRectF.left mCurrentProgressPosition;canvas.drawRect(mWhiteRectF, mWhitePaint);// 绘制叶子drawLeafs(canvas);// 2.绘制Orange ARCcanvas.drawArc(mArcRectF, 90, 180, false, mOrangePaint);// 3.绘制orange RECTmOrangeRectF.left mArcRightLocation;mOrangeRectF.right mCurrentProgressPosition;canvas.drawRect(mOrangeRectF, mOrangePaint);}}/*** 绘制叶子* * param canvas*/private void drawLeafs(Canvas canvas) {mLeafRotateTime mLeafRotateTime 0 ? LEAF_ROTATE_TIME : mLeafRotateTime;long currentTime System.currentTimeMillis();for (int i 0; i mLeafInfos.size(); i) {Leaf leaf mLeafInfos.get(i);if (currentTime leaf.startTime leaf.startTime ! 0) {// 绘制叶子根据叶子的类型和当前时间得出叶子的xygetLeafLocation(leaf, currentTime);// 根据时间计算旋转角度canvas.save();// 通过Matrix控制叶子旋转Matrix matrix new Matrix();float transX mLeftMargin leaf.x;float transY mLeftMargin leaf.y;Log.i(TAG, left.x leaf.x --leaf.y leaf.y);matrix.postTranslate(transX, transY);// 通过时间关联旋转角度则可以直接通过修改LEAF_ROTATE_TIME调节叶子旋转快慢float rotateFraction ((currentTime - leaf.startTime) % mLeafRotateTime)/ (float) mLeafRotateTime;int angle (int) (rotateFraction * 360);// 根据叶子旋转方向确定叶子旋转角度int rotate leaf.rotateDirection 0 ? angle leaf.rotateAngle : -angle leaf.rotateAngle;matrix.postRotate(rotate, transX mLeafWidth / 2, transY mLeafHeight / 2);canvas.drawBitmap(mLeafBitmap, matrix, mBitmapPaint);canvas.restore();} else {continue;}}}private void getLeafLocation(Leaf leaf, long currentTime) {long intervalTime currentTime - leaf.startTime;mLeafFloatTime mLeafFloatTime 0 ? LEAF_FLOAT_TIME : mLeafFloatTime;if (intervalTime 0) {return;} else if (intervalTime mLeafFloatTime) {leaf.startTime System.currentTimeMillis() new Random().nextInt((int) mLeafFloatTime);}float fraction (float) intervalTime / mLeafFloatTime;leaf.x (int) (mProgressWidth - mProgressWidth * fraction);leaf.y getLocationY(leaf);}// 通过叶子信息获取当前叶子的Y值private int getLocationY(Leaf leaf) {// y A(wxQ)hfloat w (float) ((float) 2 * Math.PI / mProgressWidth);float a mMiddleAmplitude;switch (leaf.type) {case LITTLE:// 小振幅 中等振幅 振幅差a mMiddleAmplitude - mAmplitudeDisparity;break;case MIDDLE:a mMiddleAmplitude;break;case BIG:// 小振幅 中等振幅 振幅差a mMiddleAmplitude mAmplitudeDisparity;break;default:break;}Log.i(TAG, ---a a ---w w --leaf.x leaf.x);return (int) (a * Math.sin(w * leaf.x)) mArcRadius * 2 / 3;}Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);Log.i(test, widthMeasureSpecMeasureSpec.getSize(widthMeasureSpec),heightMeasureSpecMeasureSpec.getSize(heightMeasureSpec));int wMeasureSpec.getSize(widthMeasureSpec);int hMeasureSpec.getSize(heightMeasureSpec);mTotalWidth w;mTotalHeight h;mProgressWidth mTotalWidth - mLeftMargin - mRightMargin;mArcRadius (mTotalHeight - 2 * mLeftMargin) / 2;mOuterSrcRect new Rect(0, 0, mOuterWidth, mOuterHeight);mOuterDestRect new Rect(0, 0, mTotalWidth, mTotalHeight);mWhiteRectF new RectF(mLeftMargin mCurrentProgressPosition, mLeftMargin, mTotalWidth- mRightMargin,mTotalHeight - mLeftMargin);mOrangeRectF new RectF(mLeftMargin mArcRadius, mLeftMargin,mCurrentProgressPosition, mTotalHeight - mLeftMargin);mArcRectF new RectF(mLeftMargin, mLeftMargin, mLeftMargin 2 * mArcRadius,mTotalHeight - mLeftMargin);mArcRightLocation mLeftMargin mArcRadius;}private void initBitmap() {mLeafBitmap ((BitmapDrawable) mResources.getDrawable(R.drawable.leaf)).getBitmap();mLeafWidth mLeafBitmap.getWidth();mLeafHeight mLeafBitmap.getHeight();mOuterBitmap ((BitmapDrawable) mResources.getDrawable(R.drawable.leaf_kuang)).getBitmap();mOuterWidth mOuterBitmap.getWidth();mOuterHeight mOuterBitmap.getHeight();}/* Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mTotalWidth w;mTotalHeight h;Log.i(test, mTotalWidth w,mTotalHeighthgetWidth()getWidth(),getHeightgetHeight());mProgressWidth mTotalWidth - mLeftMargin - mRightMargin;mArcRadius (mTotalHeight - 2 * mLeftMargin) / 2;mOuterSrcRect new Rect(0, 0, mOuterWidth, mOuterHeight);mOuterDestRect new Rect(0, 0, mTotalWidth, mTotalHeight);mWhiteRectF new RectF(mLeftMargin mCurrentProgressPosition, mLeftMargin, mTotalWidth- mRightMargin,mTotalHeight - mLeftMargin);mOrangeRectF new RectF(mLeftMargin mArcRadius, mLeftMargin,mCurrentProgressPosition, mTotalHeight - mLeftMargin);mArcRectF new RectF(mLeftMargin, mLeftMargin, mLeftMargin 2 * mArcRadius,mTotalHeight - mLeftMargin);mArcRightLocation mLeftMargin mArcRadius;}*/private enum StartType {LITTLE, MIDDLE, BIG}/*** 叶子对象用来记录叶子主要数据* * author Ajian_Studio*/private class Leaf {// 在绘制部分的位置float x, y;// 控制叶子飘动的幅度StartType type;// 旋转角度int rotateAngle;// 旋转方向--0代表顺时针1代表逆时针int rotateDirection;// 起始时间(ms)long startTime;}private class LeafFactory {private static final int MAX_LEAFS 8;Random random new Random();// 生成一个叶子信息public Leaf generateLeaf() {Leaf leaf new Leaf();int randomType random.nextInt(3);// 随时类型 随机振幅StartType type StartType.MIDDLE;switch (randomType) {case 0:break;case 1:type StartType.LITTLE;break;case 2:type StartType.BIG;break;default:break;}leaf.type type;// 随机起始的旋转角度leaf.rotateAngle random.nextInt(360);// 随机旋转方向顺时针或逆时针leaf.rotateDirection random.nextInt(2);// 为了产生交错的感觉让开始的时间有一定的随机性mLeafFloatTime mLeafFloatTime 0 ? LEAF_FLOAT_TIME : mLeafFloatTime;mAddTime random.nextInt((int) (mLeafFloatTime * 2));leaf.startTime System.currentTimeMillis() mAddTime;return leaf;}// 根据最大叶子数产生叶子信息public ListLeaf generateLeafs() {return generateLeafs(MAX_LEAFS);}// 根据传入的叶子数量产生叶子信息public ListLeaf generateLeafs(int leafSize) {ListLeaf leafs new LinkedListLeaf();for (int i 0; i leafSize; i) {leafs.add(generateLeaf());}return leafs;}}/*** 设置中等振幅* * param amplitude*/public void setMiddleAmplitude(int amplitude) {this.mMiddleAmplitude amplitude;}/*** 设置振幅差* * param disparity*/public void setMplitudeDisparity(int disparity) {this.mAmplitudeDisparity disparity;}/*** 获取中等振幅* * param amplitude*/public int getMiddleAmplitude() {return mMiddleAmplitude;}/*** 获取振幅差* * param disparity*/public int getMplitudeDisparity() {return mAmplitudeDisparity;}/*** 设置进度* * param progress*/public void setProgress(int progress) {this.mProgress progress;postInvalidate();}/*** 设置叶子飘完一个周期所花的时间* * param time*/public void setLeafFloatTime(long time) {this.mLeafFloatTime time;}/*** 设置叶子旋转一周所花的时间* * param time*/public void setLeafRotateTime(long time) {this.mLeafRotateTime time;}/*** 获取叶子飘完一个周期所花的时间*/public long getLeafFloatTime() {mLeafFloatTime mLeafFloatTime 0 ? LEAF_FLOAT_TIME : mLeafFloatTime;return mLeafFloatTime;}/*** 获取叶子旋转一周所花的时间*/public long getLeafRotateTime() {mLeafRotateTime mLeafRotateTime 0 ? LEAF_ROTATE_TIME : mLeafRotateTime;return mLeafRotateTime;}
}
activity package com.example.csdnblog4;import java.util.Random;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;public class LeafLoadingActivity extends Activity implements OnSeekBarChangeListener,OnClickListener {Handler mHandler new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case REFRESH_PROGRESS:if (mProgress 40) {mProgress 1;// 随机800ms以内刷新一次mHandler.sendEmptyMessageDelayed(REFRESH_PROGRESS,new Random().nextInt(800));mLeafLoadingView.setProgress(mProgress);} else {mProgress 1;// 随机1200ms以内刷新一次mHandler.sendEmptyMessageDelayed(REFRESH_PROGRESS,new Random().nextInt(1200));mLeafLoadingView.setProgress(mProgress);}break;default:break;}};};private static final int REFRESH_PROGRESS 0x10;private LeafLoadingView mLeafLoadingView;private SeekBar mAmpireSeekBar;private SeekBar mDistanceSeekBar;private TextView mMplitudeText;private TextView mDisparityText;private View mFanView;private Button mClearButton;private int mProgress 0;private TextView mProgressText;private View mAddProgress;private SeekBar mFloatTimeSeekBar;private SeekBar mRotateTimeSeekBar;private TextView mFloatTimeText;private TextView mRotateTimeText;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.leaf_loading_layout);initViews();mHandler.sendEmptyMessageDelayed(REFRESH_PROGRESS, 3000);}private void initViews() {mFanView findViewById(R.id.fan_pic);RotateAnimation rotateAnimation AnimationUtils.initRotateAnimation(false, 1500, true,Animation.INFINITE);mFanView.startAnimation(rotateAnimation);mClearButton (Button) findViewById(R.id.clear_progress);mClearButton.setOnClickListener(this);mLeafLoadingView (LeafLoadingView) findViewById(R.id.leaf_loading);mMplitudeText (TextView) findViewById(R.id.text_ampair);mMplitudeText.setText(getString(R.string.current_mplitude,mLeafLoadingView.getMiddleAmplitude()));mDisparityText (TextView) findViewById(R.id.text_disparity);mDisparityText.setText(getString(R.string.current_Disparity,mLeafLoadingView.getMplitudeDisparity()));mAmpireSeekBar (SeekBar) findViewById(R.id.seekBar_ampair);mAmpireSeekBar.setOnSeekBarChangeListener(this);mAmpireSeekBar.setProgress(mLeafLoadingView.getMiddleAmplitude());mAmpireSeekBar.setMax(50);mDistanceSeekBar (SeekBar) findViewById(R.id.seekBar_distance);mDistanceSeekBar.setOnSeekBarChangeListener(this);mDistanceSeekBar.setProgress(mLeafLoadingView.getMplitudeDisparity());mDistanceSeekBar.setMax(20);mAddProgress findViewById(R.id.add_progress);mAddProgress.setOnClickListener(this);mProgressText (TextView) findViewById(R.id.text_progress);mFloatTimeText (TextView) findViewById(R.id.text_float_time);mFloatTimeSeekBar (SeekBar) findViewById(R.id.seekBar_float_time);mFloatTimeSeekBar.setOnSeekBarChangeListener(this);mFloatTimeSeekBar.setMax(5000);mFloatTimeSeekBar.setProgress((int) mLeafLoadingView.getLeafFloatTime());mFloatTimeText.setText(getResources().getString(R.string.current_float_time,mLeafLoadingView.getLeafFloatTime()));mRotateTimeText (TextView) findViewById(R.id.text_rotate_time);mRotateTimeSeekBar (SeekBar) findViewById(R.id.seekBar_rotate_time);mRotateTimeSeekBar.setOnSeekBarChangeListener(this);mRotateTimeSeekBar.setMax(5000);mRotateTimeSeekBar.setProgress((int) mLeafLoadingView.getLeafRotateTime());mRotateTimeText.setText(getResources().getString(R.string.current_float_time,mLeafLoadingView.getLeafRotateTime()));}Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {if (seekBar mAmpireSeekBar) {mLeafLoadingView.setMiddleAmplitude(progress);mMplitudeText.setText(getString(R.string.current_mplitude,progress));} else if (seekBar mDistanceSeekBar) {mLeafLoadingView.setMplitudeDisparity(progress);mDisparityText.setText(getString(R.string.current_Disparity,progress));} else if (seekBar mFloatTimeSeekBar) {mLeafLoadingView.setLeafFloatTime(progress);mFloatTimeText.setText(getResources().getString(R.string.current_float_time,progress));}else if (seekBar mRotateTimeSeekBar) {mLeafLoadingView.setLeafRotateTime(progress);mRotateTimeText.setText(getResources().getString(R.string.current_rotate_time,progress));}}Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}Overridepublic void onClick(View v) {if (v mClearButton) {mLeafLoadingView.setProgress(0);mHandler.removeCallbacksAndMessages(null);mProgress 0;} else if (v mAddProgress) {mProgress;mLeafLoadingView.setProgress(mProgress);mProgressText.setText(String.valueOf(mProgress));}}
}
layout
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:background#fed255android:orientationvertical TextViewandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_gravitycenter_horizontalandroid:layout_marginTop100dpandroid:textloading ...android:textColor#FFA800android:textSize 30dp /RelativeLayoutandroid:idid/leaf_contentandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_marginTop50dp com.example.csdnblog4.LeafLoadingViewandroid:idid/leaf_loadingandroid:layout_width302dpandroid:layout_height61dpandroid:layout_centerHorizontaltrue /ImageViewandroid:idid/fan_picandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_alignParentRighttrueandroid:layout_centerVerticaltrueandroid:layout_marginRight35dpandroid:srcdrawable/fengshan //RelativeLayoutScrollViewandroid:layout_widthmatch_parentandroid:layout_heightmatch_parent LinearLayoutandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationvertical LinearLayoutandroid:idid/seek_content_oneandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_marginLeft15dpandroid:layout_marginRight15dpandroid:layout_marginTop15dp TextViewandroid:idid/text_ampairandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_gravitycenter_verticalandroid:textColor#ffffa800android:textSize15dp /SeekBarandroid:idid/seekBar_ampairandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_marginLeft5dpandroid:layout_weight1 //LinearLayoutLinearLayoutandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_marginLeft15dpandroid:layout_marginRight15dpandroid:layout_marginTop15dpandroid:orientationhorizontal TextViewandroid:idid/text_disparityandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_gravitycenter_verticalandroid:textColor#ffffa800android:textSize15dp /SeekBarandroid:idid/seekBar_distanceandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_marginLeft5dpandroid:layout_weight1 //LinearLayoutLinearLayoutandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_marginLeft15dpandroid:layout_marginRight15dpandroid:layout_marginTop15dpandroid:orientationhorizontal TextViewandroid:idid/text_float_timeandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_gravitycenter_verticalandroid:textColor#ffffa800android:textSize15dp /SeekBarandroid:idid/seekBar_float_timeandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_marginLeft5dpandroid:layout_weight1 //LinearLayoutLinearLayoutandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_marginLeft15dpandroid:layout_marginRight15dpandroid:layout_marginTop15dpandroid:orientationhorizontal TextViewandroid:idid/text_rotate_timeandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_gravitycenter_verticalandroid:textColor#ffffa800android:textSize15dp /SeekBarandroid:idid/seekBar_rotate_timeandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_marginLeft5dpandroid:layout_weight1 //LinearLayoutButtonandroid:idid/clear_progressandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_marginTop15dpandroid:text去除进度条,玩转弧线android:textSize18dp /LinearLayoutandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_marginLeft15dpandroid:layout_marginRight15dpandroid:layout_marginTop15dpandroid:orientationhorizontal Buttonandroid:idid/add_progressandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text增加进度: android:textSize18dp /TextViewandroid:idid/text_progressandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_gravitycenter_verticalandroid:textColor#ffffa800android:textSize15dp //LinearLayout/LinearLayout/ScrollView/LinearLayout
注意
本文中用到了onSizeChanged方法这个方法在这是为了自适应界面每次界面变化的时候都会被调用来重新计算一些参数一般在刚进入与横竖屏切换时调用
参考链接
Android自定义View初步 - 泡在网上的日子
本文中还用到了postInvalidate
invalidate()和postInvalidate() 的区别及使用 Android提供了Invalidate方法实现界面刷新但是Invalidate不能直接在线程中调用因为他是违背了单线程模型Android UI操作并不是线程安全的并且这些操作必须在UI线程中调用。 invalidate()是用来刷新View的必须是在UI线程中进行工作。比如在修改某个view的显示时调用invalidate()才能看到重新绘制的界面。invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。 一个Android 程序默认情况下也只有一个进程但一个进程下却可以有许多个线程。 在这么多线程当中把主要是负责控制UI界面的显示、更新和控件交互的线程称为UI线程由于onCreate()方法是由UI线程执行的所以也可以把UI线程理解为主线程。其余的线程可以理解为工作者线程。 invalidate()得在UI线程中被调动在工作者线程中可以通过Handler来通知UI线程进行界面更新。
而postInvalidate()在工作者线程中被调用
参考链接
Android笔记invalidate()和postInvalidate() 的区别及使用 - Mars2639——求知de路上 - 博客频道 - CSDN.NET
本文还涉及到单位的转化
参考链接
Android中dip、dp、sp、pt和px的区别 - 大气象 - 博客园
最终效果如下 参考链接
一个绚丽的loading动效分析与实现 - Ajian_studio - 博客频道 - CSDN.NET
源代码下载
源代码
完成