转载请注明出处:王亟亟的大牛之路

近期看了一大堆的自己定义View多数都能够充当耗时操作的交互界面。再接再厉再传一个SubmitView。一个和可用于模仿提交等待与用户交互用的一个自己定义View

效果图:

项目结构:



一个Android Studio项目。也能够转成Eclipse,由于没有涉及到打包啊lib的一些操作。连资源文件都没用,所以能够直接Copy过去。

自己定义View

public class SubmitView extends View {

    private static final int COLOR_BACK = 0xff00cd97;
private static final int COLOR_GREY = 0xffb9b9b9; private int mColor = COLOR_BACK; //
private Paint mBorderPaint;
private Paint mTextPaint;
private Paint mBackPaint; private int mWidth;
private int mHeight;
private int mRadius;
private static final int PADDING = 5; private Rect mTextBounds; private boolean mShowText = true;
private static final String TEXT_SUBMIT = "提交";
private String mText = TEXT_SUBMIT;
private int mStrokeWidth; // indicate if view can click
private boolean mCanClick = true; // indicate the animator state
private AniState mAniState = AniState.INIT; private boolean mIfReset = false; enum AniState {
INIT,
FIRST_START, // start animation which change backcolor and text color
FIRST_STOP,
SECOND_START, // second animation which change "submit" size for a while
SECOND_STOP,
THIRD_START, // third animation which convert to circle and change back color
THIRD_STOP,
FOURTH_START, // fourth animation which show the progress
FOURTH_STOP,
FIFTH_START, // fifth animation which can narrow the back and border and show "correct" sign
FIFTH_STOP; public boolean isPlaying() {
return this==FIRST_START
|| this==SECOND_START
|| this == THIRD_START
|| this == FOURTH_START
|| this == FIFTH_START;
} @Override
public String toString() {
switch (this) {
case INIT:
return "***init***";
case FIRST_START:
return "***first start***";
case FIRST_STOP:
return "***first stop***";
case SECOND_START:
return "***second start***";
case SECOND_STOP:
return "***second stop***";
case THIRD_START:
return "***third start***";
case THIRD_STOP:
return "****third stop**";
case FOURTH_START:
return "***fourth start***";
case FOURTH_STOP:
return "***fourth stop***";
case FIFTH_START:
return "***fifth start***";
case FIFTH_STOP:
return "***fifth stop";
default:
return "unknown state";
}
}
} public SubmitView(Context context) {
this(context, null, 0);
} public SubmitView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public SubmitView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs, defStyleAttr);
} private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
mBorderPaint = new Paint();
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(5);
mBorderPaint.setAntiAlias(true); mBackPaint = new Paint();
mBackPaint.setAntiAlias(true);
mBackPaint.setStyle(Paint.Style.FILL); mTextPaint = new Paint();
mTextPaint.setAntiAlias(true); mTextBounds = new Rect();
mCanClick = true; mProgress = 0;
mTargetProgress = 0; setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mCanClick) {
mCanClick = false;
if (mAniState == AniState.INIT) {
mAniState = AniState.FIRST_START;
firstAniStart();
invalidate();
}
}
}
}); } private void firstAniStart() {
mFirstStartT = System.currentTimeMillis();
mFirstStopT = mFirstStartT + FIRST_DURATION;
} @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
mWidth = getWidth();
mHeight = getHeight();
int width = mWidth - (PADDING * 2);
int height = mHeight - (PADDING * 2);
mRadius = width/3 > height ? height/2 : width/6;
mStrokeWidth = mRadius/12;
mBorderPaint.setStrokeWidth(mStrokeWidth);
// Log.i("SubmitView", "width=" + mWidth + ", height=" + mHeight + ", radius=" + mRadius + ", strokeWidth=" + mStrokeWidth);
}
} private RectF rectF = new RectF(); @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i("submit", "cur state: " + mAniState); // open for debug switch (mAniState) {
case INIT:
mBorderPaint.setColor(mColor);
mBackPaint.setColor(mColor);
mTextPaint.setColor(mColor);
canvas.drawRoundRect(new RectF(PADDING, mHeight / 2 - mRadius, mWidth - PADDING, mHeight / 2 + mRadius), mRadius, mRadius, mBorderPaint);
mTextPaint.setTextSize(mRadius/2);
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds);
canvas.drawText(mText, mWidth / 2 - mTextBounds.width() / 2, mHeight / 2 + mTextBounds.height() / 2, mTextPaint);
break;
case FIRST_START:
canvas.drawRoundRect(new RectF(PADDING, mHeight / 2 - mRadius, mWidth - PADDING, mHeight / 2 + mRadius), mRadius, mRadius, mBorderPaint);
mBackPaint.setColor(getFirstColor());
canvas.drawRoundRect(new RectF(PADDING, mHeight / 2 - mRadius, mWidth - PADDING, mHeight / 2 + mRadius),
mRadius, mRadius, mBackPaint);
mTextPaint.setColor(getFirstTextColor());
canvas.drawText(mText, mWidth/2 - mTextBounds.width()/2, mHeight/2 + mTextBounds.height()/2, mTextPaint);
break;
case SECOND_START:
canvas.drawRoundRect(new RectF(PADDING, mHeight / 2 - mRadius, mWidth - PADDING, mHeight / 2 + mRadius), mRadius, mRadius, mBorderPaint);
canvas.drawRoundRect(new RectF(PADDING, mHeight / 2 - mRadius, mWidth - PADDING, mHeight / 2 + mRadius),
mRadius, mRadius, mBackPaint);
mTextPaint.setTextSize(getSecondTextSize());
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds);
canvas.drawText(mText, mWidth/2 - mTextBounds.width()/2, mHeight/2 + mTextBounds.height()/2, mTextPaint);
break;
case THIRD_START:
int leftRect = mWidth/2 - getHorizonRadius();
int rightRect = mWidth/2 + getHorizonRadius();
mBackPaint.setColor(getThirdColor());
canvas.drawRoundRect(new RectF(leftRect, mHeight / 2 - mRadius, rightRect, mHeight / 2 + mRadius),
mRadius, mRadius, mBackPaint);
mBorderPaint.setColor(getThirdBorderColor());
canvas.drawRoundRect(new RectF(leftRect, mHeight / 2 - mRadius, rightRect, mHeight / 2 + mRadius), mRadius, mRadius, mBorderPaint);
break;
case FOURTH_START:
// Log.i("submit", "" + progress);
if (mProgress>=1) {
if (mOnProgressDone!=null) {
mOnProgressDone.progressDone();
}
mAniState = AniState.FOURTH_STOP;
mAniState = AniState.FIFTH_START;
initFifthAni();
}
mBorderPaint.setColor(COLOR_GREY);
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius, mBorderPaint);
mBorderPaint.setColor(mColor);
canvas.drawArc(new RectF(mWidth / 2 - mRadius, mHeight / 2 - mRadius, mWidth / 2 + mRadius, mHeight/2 + mRadius),
START_DEGREE, 360 * mProgress, false, mBorderPaint);
if (mProgress < mTargetProgress) {
mProgress += 0.005;
mProgress = Math.min(mProgress, 1);
}
break;
case FIFTH_START:
int leftFifthR = mWidth/2 - getFifthHorizonR();
int rightFifthR = mWidth/2 + getFifthHorizonR();
canvas.drawRoundRect(new RectF(leftFifthR, mHeight/2-mRadius, rightFifthR, mHeight/2 + mRadius),
mRadius, mRadius, mBorderPaint);
mBackPaint.setColor(getFifthColor());
canvas.drawRoundRect(new RectF(leftFifthR, mHeight / 2 - mRadius, rightFifthR, mHeight / 2 + mRadius),
mRadius, mRadius, mBackPaint);
drawCorrectSign(canvas, getFifthRatio());
if (getFifthRatio()>=1 && mIfReset) {
Log.i("submit", "reset is valid");
mIfReset = false;
mAniState = AniState.INIT;
initView(null, null, 0);
invalidate();
}
break;
case FIFTH_STOP:
canvas.drawRoundRect(new RectF(PADDING, mHeight/2 - mRadius, mWidth - PADDING, mHeight/2 + mRadius),
mRadius, mRadius, mBorderPaint);
canvas.drawRoundRect(new RectF(PADDING, mHeight/2 - mRadius, mWidth - PADDING, mHeight/2 + mRadius),
mRadius, mRadius, mBackPaint);
drawCorrectSign(canvas, 1);
break;
} if (mAniState.isPlaying()) {
invalidate();
} } // private int forDeubug = 0; // to count for debug // first animation
private static final int FIRST_DURATION = 300;
private long mFirstStartT;
private long mFirstStopT; private float getFirstRatio() {
long now = System.currentTimeMillis();
if (now >= mFirstStopT) {
mAniState = AniState.FIRST_STOP;
mAniState = AniState.SECOND_START;
initSecAni();
return 1;
}
float ratio = (float)(now - mFirstStartT) / (float) FIRST_DURATION; return ratio > 1 ? 1 : ratio; } private int getFirstColor() { return Color.argb(getFirstRatio()==1 ? 0xff : (int)(getFirstRatio() * 0xff), Color.red(mColor), Color.green(mColor), Color.blue(mColor));
} private int getFirstTextColor() {
float ratio = getFirstRatio();
if (ratio==1) {
return 0xffffffff;
}
int startRed = Color.red(mColor);
int red = startRed + (int) ((0xff - startRed) * ratio); int startGreen = Color.green(mColor);
int green = startGreen + (int) ((0xff - startGreen) * ratio); int startBlue = Color.blue(mColor);
int blue = startBlue + (int) ((0xff - startBlue) * ratio); return Color.argb(0xff, red, green, blue);
} // second animation which resize the "submit" size
private static final long SECOND_DURATION = 300;
private long mSecStartT;
private long mSecStopT; private void initSecAni() {
mSecStartT = System.currentTimeMillis();
mSecStopT = mSecStartT + SECOND_DURATION;
} private float getSecondTextSize() {
long now = System.currentTimeMillis();
if (now >= mSecStopT) {
mAniState = AniState.SECOND_STOP;
mAniState = AniState.THIRD_START;
initThirdAni();
return mRadius/2;
} float ratio = (now - (mSecStartT + SECOND_DURATION/2))/(float)(SECOND_DURATION/2);
return mRadius*3/8 + mRadius/8 * Math.abs(ratio);
} // third animation which change back color and change to a circle
private long mThirdStartT;
private long mThirdStopT;
private long THIRD_DURATION = 400; private void initThirdAni() {
mThirdStartT = System.currentTimeMillis();
mThirdStopT = mThirdStartT + THIRD_DURATION;
} private float getThirdRatio() {
long now = System.currentTimeMillis();
if (now >= mThirdStopT) {
mAniState = AniState.THIRD_STOP;
mAniState = AniState.FOURTH_START;
initFourthAni();
return 1;
} float ratio = (now - mThirdStartT)/(float)THIRD_DURATION;
return ratio >= 1 ? 1 : ratio;
} private int getHorizonRadius() {
float ratio = getThirdRatio();
int horizonRadius = mRadius + (int) ((1-ratio) * (mWidth/2 - PADDING - mRadius));
return horizonRadius;
} private int getThirdColor() {
float ratio = getThirdRatio();
int alpha = (int) ((1-ratio) * 0xff);
return Color.argb(alpha, Color.red(mColor), Color.green(mColor), Color.blue(mColor));
} private int getThirdBorderColor() {
float ratio = getThirdRatio();
int redStart = Color.red(mColor);
int greenStart = Color.green(mColor);
int blueStart = Color.blue(mColor); int curRed = redStart + (int) ((Color.red(COLOR_GREY) - redStart) * ratio);
int curGreen = greenStart + (int) ((Color.green(COLOR_GREY) - greenStart) * ratio);
int curBlue = blueStart + (int) ((Color.blue(COLOR_GREY) - blueStart) * ratio); return Color.argb(0xff, curRed, curGreen, curBlue);
} // used for fourth animation but this not use time to calculate animation
private static final int START_DEGREE = 270;
private float mProgress = 0f;
private float mTargetProgress = mProgress; private OnProgressDone mOnProgressDone;
private OnProgressStart mOnProgressStart; // listener for when progress start private void initFourthAni() {
if (mOnProgressStart!=null) {
mOnProgressStart.progressStart();
}
} // set current progress
public void setProgress(float progress) {
mTargetProgress = progress > 1 ? 1 : progress;
} public void setOnProgressDone(OnProgressDone onProgressDone) {
mOnProgressDone = onProgressDone;
} public void setOnProgressStart(OnProgressStart onProgressStart) {
mOnProgressStart = onProgressStart;
}
public boolean isProgressDone() {
return mAniState== AniState.FOURTH_STOP
|| mAniState == AniState.FIFTH_START
|| mAniState == AniState.FIFTH_STOP;
} public void setText(String str) {
if (str==null || TextUtils.isEmpty(str)) {
throw new IllegalArgumentException("text can't be null or empty");
}
mText = str;
} public void reset() {
mIfReset = true;
} public void setBackColor(int color) {
mColor = color;
invalidate();
} // used for fifth animation by time private static final long FIFTH_DURATION = 600;
private long mFifthStartT;
private long mFifthStopT; private void initFifthAni() {
mFifthStartT = System.currentTimeMillis();
mFifthStopT = mFifthStartT + FIFTH_DURATION; } private float getFifthRatio() {
long now = System.currentTimeMillis();
if (now >= mFifthStopT) {
mAniState = AniState.FIFTH_STOP;
return 1;
}
float ratio = (now - mFifthStartT) / (float) FIFTH_DURATION;
return ratio >= 1 ? 1 : ratio;
} private int getFifthHorizonR() {
float ratio = getFifthRatio();
if (ratio==1) {
return mWidth/2 - PADDING;
}
int horizonR = mRadius + (int) (((mWidth/2 - PADDING) - mRadius) * ratio);
return horizonR;
} private int getFifthColor() {
float ratio = getFifthRatio();
if (ratio==1) {
return mColor;
}
int alpha = (int) (ratio * 0xff);
return Color.argb(alpha, Color.red(mColor), Color.green(mColor), Color.blue(mColor)); } // drawing "correct" sign
private void drawCorrectSign(Canvas canvas, float ratio) { Paint correctPaint = new Paint();
correctPaint.setAntiAlias(true);
correctPaint.setStyle(Paint.Style.STROKE);
correctPaint.setStrokeWidth(10f);
correctPaint.setColor(0xffffffff);
correctPaint.setDither(true);
correctPaint.setStrokeJoin(Paint.Join.ROUND);
correctPaint.setStrokeCap(Paint.Cap.ROUND);
// correctPaint.setPathEffect(new CornerPathEffect(5)); int centerX = mWidth/2;
int centerY = mHeight/2 + mRadius/4; Path path = new Path();
path.moveTo(centerX - (mRadius*ratio/4), centerY - (mRadius*ratio/4));
path.lineTo(centerX, centerY);
path.lineTo(centerX + (mRadius*ratio/2), centerY -(mRadius*ratio/2)); canvas.drawPath(path, correctPaint);
} public interface OnProgressDone {
void progressDone();
}
public interface OnProgressStart {
void progressStart();
}
}

分析:

详细的实现,待会看源代码吧,给伸手党几个使用的得到的地方

private static final String TEXT_SUBMIT 初始化看到试图时的那个 String 上图为Submit

操作结束后调用的方法

public interface OnProgressDone {
void progressDone();
}

操作開始时调用的方法

 public interface OnProgressStart {
void progressStart();
}

控制进度的方法(名为setProgress可是实质上仅仅分1和0。0就停止,1就是继续,而且 不管你传入的參数>1或者等于1都没有差别,假设你開始时传入1,执行过程中不传0,那么动画走完时候就切换到操作成功的界面了。所以须要暂停的话,要在适当的地方调用setProgress(0))

 public void setProgress(float progress) {
mTargetProgress = progress > 1 ? 1 : progress;
}

今天一下子看了4篇。。。有点累的。。

下班!!

源代码地址:http://yunpan.cn/cdDeLvTEeQeTk 訪问password 0475

android 自己定义View之SubmitView的更多相关文章

  1. Android 自己定义View (二) 进阶

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自己定义View之旅.前面已经介绍过一个自己定义View的基础 ...

  2. Android 自己定义View须要重写ondraw()等方法

    Android  自己定义View须要重写ondraw()等方法.这篇博客给大家说说自己定义View的写法,须要我们继承View,然后重写一些 方法,方法多多,看你须要什么方法 首先写一个自己定义的V ...

  3. 【Android自己定义View实战】之自己定义超简单SearchView搜索框

    [Android自己定义View实战]之自己定义超简单SearchView搜索框 这篇文章是对之前文章的翻新,至于为什么我要又一次改动这篇文章?原因例如以下 1.有人举报我抄袭,原文链接:http:/ ...

  4. Android 自己定义View学习(2)

    上一篇学习了基本使用方法,今天学一下略微复杂一点的.先看一下效果图 为了完毕上面的效果还是要用到上一期开头的四步 1,属性应该要有颜色,要有速度 <?xml version="1.0& ...

  5. Android自己定义view之measure、layout、draw三大流程

    自己定义view之measure.layout.draw三大流程 一个view要显示出来.须要经过測量.布局和绘制这三个过程,本章就这三个流程具体探讨一下.View的三大流程具体分析起来比較复杂,本文 ...

  6. 手把手带你画一个 时尚仪表盘 Android 自己定义View

    拿到美工效果图.咱们程序猿就得画得一模一样. 为了不被老板喷,仅仅能多练啊. 听说你认为前面几篇都so easy,那今天就带你做个相对照较复杂的. 转载请注明出处:http://blog.csdn.n ...

  7. Android自己定义View的实现方法

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17357967 不知不觉中,带你一步步深入了解View系列的文章已经写到第四篇了.回 ...

  8. Android自己定义View基础篇(三)之SwitchButton开关

    自己定义View基础篇(二) 自己定义View基础篇(一) 自己定义View原理 我在解说之前,先来看看效果图,有图有真相:(转换gif图片效果太差) 那来看看真实图片: 假设你要更改样式,请改动例如 ...

  9. Android 自己定义View (四) 视频音量调控

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24529807 今天没事逛eoe,看见有人求助要做一个以下的效果,我看以下一哥们说 ...

随机推荐

  1. win2003系统同步Linux ntp server批处理

    最后更新时间: 2018/12/15 一般windows配置时间服务器,只需要在windows系统右下角,点时间,里面配置好对应NTP服务器地址就行, 至多再修改一下注册表 HKEY_LOCAL_MA ...

  2. whatis---查询一个命令执行什么功能

    whatis命令是用于查询一个命令执行什么功能,并将查询结果打印到终端上. whatis命令在用catman -w命令创建的数据库中查找command参数指定的命令.系统调用.库函数或特殊文件名.wh ...

  3. ECNUOJ 2142 放书

    放书 Time Limit:1000MS Memory Limit:65536KBTotal Submit:409 Accepted:173 Description  你要把一叠书放进一些箱子里面,为 ...

  4. ArcGIS api for javascript——加入地图并显示当前地图范围

    描述 这个示例使用Map.extent property属性接收地图范围的左下角和右上角坐标 "书签". 使用下列行创建地图: var map = new esri.Map(&qu ...

  5. Java接口源码--System和应用程序进程间通信

    本文參考<Android系统源代码情景分析>.作者罗升阳 一.架构代码: ~/Android/frameworks/base/core/java/android/os ----IInter ...

  6. 11.ng-init

    转自:https://www.cnblogs.com/best/tag/Angular/ 初始化 <p ng-init="test=1" ng-repeat="a ...

  7. quartz 添加监听器listener

    全局注册,所有Job都会起作用 JobCountListener listener = new JobCountListener(); sched.getListenerManager().addJo ...

  8. 安装vnc出现的问题

    重启vnc 命令:/sbin/service vncserver start或者vncserver VNC的启动/停止/重启 #service vncserver start/stop/restart ...

  9. 洛谷T21776 子序列

    题目描述 你有一个长度为 nn 的数列 \{a_n\}{an​} ,这个数列由 0,10,1 组成,进行 mm 个的操作: 1~l~r1 l r :把数列区间 [l, r][l,r] 内的所有数取反. ...

  10. happy Mom ——php mysqli DES加密

    看完<爱你就像爱生命>这本书,真的看出小波哥很有才,跟小波哥比起来,我唯一拿的出手的可能就是我比他的颜值了.想起一句话,人不是因为美丽而可爱,而是因为可爱而美丽.所以我对我的要求是,继续修 ...