Android常用开源项目(十八)

Android开发之实现炫酷的加载样式

1.在Android的网路请求时,经常会遇到需要重写加载样式的定义。有时候为了抓住客户的眼球,需要实现一些炫酷的效果。首先我们先看下效果图吧

Android开发之实现炫酷的加载样式

加载样式一

Android开发之实现炫酷的加载样式

加载样式二

Android开发之实现炫酷的加载样式

加载样式三

Android开发之实现炫酷的加载样式

加载样式四

Android开发之实现炫酷的加载样式

加载样式五

2.下面看下具体的实现步骤了

(1).我们是在Android Studio中实现开发的

首先新建module,实现加载样式的lib包

Android开发之实现炫酷的加载样式

加载样式的代码结构图

<1>.翻书的效果实现代码

PageView.java类的实现代码

public class PageView extends View {

private Paint paint;

private Path path;

private int width;

private int height;

private float padding;

private int border;

public PageView(Context context) {

super(context);

initView();

}

public PageView(Context context, AttributeSet attrs) {

super(context, attrs);

initView();

}

public PageView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView();

}

private void initView() {

padding = getResources().getDimension(R.dimen.book_padding);

border = getResources().getDimensionPixelOffset(R.dimen.book_border);

paint = new Paint();

paint.setAntiAlias(true);

paint.setStrokeWidth(getResources().getDimension(R.dimen.page_border));

path = new Path();

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

width = w;

height = h;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

paint.setColor(getResources().getColor(R.color.book_loading_book));

paint.setStyle(Paint.Style.STROKE);

float offset = border / 4;

path.moveTo(width / 2, padding + offset);

path.lineTo(width - padding - offset, padding + offset);

path.lineTo(width - padding - offset, height - padding - offset);

path.lineTo(width / 2, height - padding - offset);

canvas.drawPath(path, paint);

paint.setColor(getResources().getColor(R.color.book_loading_page));

paint.setStyle(Paint.Style.FILL);

offset = border / 2;

canvas.drawRect(width / 2, padding + offset, width - padding - offset, height - padding - offset, paint);

}

}

BookView.java的代码实现

public class BookView extends View {

private Paint paint;

private int width;

private int height;

public BookView(Context context) {

super(context);

initView();

}

public BookView(Context context, AttributeSet attrs) {

super(context, attrs);

initView();

}

public BookView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView();

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

width = w;

height = h;

}

private void initView() {

paint = new Paint();

paint.setColor(getResources().getColor(R.color.book_loading_book));

paint.setStrokeWidth(getResources().getDimension(R.dimen.book_border));

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.STROKE);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawRect(0, 0, width, height, paint);

}

}

BookLoading.java的代码实现

public class BookLoading extends FrameLayout {

private static final long DURATION = 1000;

private static final int PAGE_NUM = 5;

private static final int DELAYED = 200;

private ArrayList<PageView> pageViews;

private BookHandler bookHandler;

private boolean isStart;

public BookLoading(Context context) {

super(context);

initView(context);

}

public BookLoading(Context context, AttributeSet attrs) {

super(context, attrs);

initView(context);

}

public BookLoading(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView(context);

}

private void initView(Context context) {

LayoutInflater.from(context).inflate(R.layout.book_loading, this, true);

pageViews = new ArrayList<>();

bookHandler=new BookHandler(this);

}

@Override

protected void onFinishInflate() {

super.onFinishInflate();

addPage();

}

private void addPage() {

LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

for (int i = 0; i < PAGE_NUM; i++) {

PageView pageView = new PageView(getContext());

addView(pageView, params);

pageView.setTag(R.string.app_name, i);

pageViews.add(pageView);

}

}

private void playAnim() {

setAnim(pageViews.get(PAGE_NUM - 1), DELAYED);

setAnim(pageViews.get(PAGE_NUM - 1), DURATION + DELAYED);

setAnim(pageViews.get(PAGE_NUM - 2), DURATION + DELAYED * 2);

for (int i = PAGE_NUM - 1; i >= 0; i--) {

setAnim(pageViews.get(i), DURATION * 3 + (PAGE_NUM - 1 - i) * DELAYED / 2);

}

}

private void setAnim(final View view, long delay) {

ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 0.0F, -180.0F);

animator.setDuration(DURATION);

animator.setStartDelay(delay);

animator.setInterpolator(new LinearInterpolator());

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

boolean change = false;

@Override

public void onAnimationUpdate(ValueAnimator animation) {

if (animation.getCurrentPlayTime() > DURATION / 2 && !change) {

change = true;

view.bringToFront();

}

}

});

animator.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

if ((int) view.getTag(R.string.app_name) == PAGE_NUM - 1) {

view.bringToFront();

}

}

@Override

public void onAnimationEnd(Animator animation) {

}

@Override

public void onAnimationCancel(Animator animation) {

}

@Override

public void onAnimationRepeat(Animator animation) {

}

});

animator.start();

}

public void start(){

isStart=true;

bookHandler.obtainMessage().sendToTarget();

}

public void stop(){

isStart=false;

bookHandler.removeCallbacks(null);

bookHandler.removeCallbacksAndMessages(null);

}

public boolean isStart(){

return isStart;

}

static class BookHandler extends Handler{

private WeakReference<BookLoading> weakReference;

public BookHandler(BookLoading bookLoading){

weakReference=new WeakReference<>(bookLoading);

}

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

BookLoading bookLoading=weakReference.get();

if (null==bookLoading)

return;

bookLoading.playAnim();

Message message=obtainMessage();

sendMessageDelayed(message,DURATION*5);

}

}

}

<2>.摆钟的动画实现

CradleBall.java的代码实现

public class CradleBall extends View {

private int width;

private int height;

private Paint paint;

public CradleBall(Context context) {

super(context);

initView();

}

public CradleBall(Context context, AttributeSet attrs) {

super(context, attrs);

initView();

}

public CradleBall(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView();

}

private void initView() {

paint = new Paint();

paint.setColor(Color.WHITE);

paint.setStyle(Paint.Style.FILL);

paint.setAntiAlias(true);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

width = w;

height = h;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawCircle(width / 2, height / 2, width / 2, paint);

}

}

NewtonCradleLoading.java的代码实现

public class NewtonCradleLoading extends LinearLayout {

private CradleBall cradleBallOne;

private CradleBall cradleBallTwo;

private CradleBall cradleBallThree;

private CradleBall cradleBallFour;

private CradleBall cradleBallFive;

private static final int DURATION = 400;

private static final int SHAKE_DISTANCE = 2;

private static final float PIVOT_X = 0.5f;

private static final float PIVOT_Y = -3f;

private static final int DEGREE = 30;

private boolean isStart = false;

public NewtonCradleLoading(Context context) {

super(context);

initView(context);

}

public NewtonCradleLoading(Context context, AttributeSet attrs) {

super(context, attrs);

initView(context);

}

public NewtonCradleLoading(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView(context);

}

private void initView(Context context) {

LayoutInflater.from(context).inflate(R.layout.newton_cradle_loading, this, true);

}

@Override

protected void onFinishInflate() {

super.onFinishInflate();

cradleBallOne = (CradleBall) findViewById(R.id.ball_one);

cradleBallTwo = (CradleBall) findViewById(R.id.ball_two);

cradleBallThree = (CradleBall) findViewById(R.id.ball_three);

cradleBallFour = (CradleBall) findViewById(R.id.ball_four);

cradleBallFive = (CradleBall) findViewById(R.id.ball_five);

initAnim();

}

RotateAnimation rotateLeftAnimation;//cradleBallOne left to right

RotateAnimation rotateRightAnimation;//cradleBallFive right to left

TranslateAnimation shakeLeftAnimation;

TranslateAnimation shakeRightAnimation;

private void initAnim() {

rotateRightAnimation = new RotateAnimation(0, -DEGREE, RotateAnimation.RELATIVE_TO_SELF, PIVOT_X, RotateAnimation.RELATIVE_TO_SELF, PIVOT_Y);

rotateRightAnimation.setRepeatCount(1);

rotateRightAnimation.setRepeatMode(Animation.REVERSE);

rotateRightAnimation.setDuration(DURATION);

rotateRightAnimation.setInterpolator(new LinearInterpolator());

rotateRightAnimation.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

if (isStart)

startRightAnim();

}

@Override

public void onAnimationRepeat(Animation animation) {

}

});

shakeLeftAnimation = new TranslateAnimation(0, SHAKE_DISTANCE, 0, 0);

shakeLeftAnimation.setDuration(DURATION);

shakeLeftAnimation.setInterpolator(new CycleInterpolator(2));

rotateLeftAnimation = new RotateAnimation(0, DEGREE, RotateAnimation.RELATIVE_TO_SELF, PIVOT_X, RotateAnimation.RELATIVE_TO_SELF, PIVOT_Y);

rotateLeftAnimation.setRepeatCount(1);

rotateLeftAnimation.setRepeatMode(Animation.REVERSE);

rotateLeftAnimation.setDuration(DURATION);

rotateLeftAnimation.setInterpolator(new LinearInterpolator());

rotateLeftAnimation.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

if (isStart) {

cradleBallTwo.startAnimation(shakeLeftAnimation);

cradleBallThree.startAnimation(shakeLeftAnimation);

cradleBallFour.startAnimation(shakeLeftAnimation);

cradleBallFive.startAnimation(rotateRightAnimation);

}

}

@Override

public void onAnimationRepeat(Animation animation) {

}

});

shakeRightAnimation = new TranslateAnimation(0, -SHAKE_DISTANCE, 0, 0);

shakeRightAnimation.setDuration(DURATION);

shakeRightAnimation.setInterpolator(new CycleInterpolator(2));

shakeRightAnimation.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

if (isStart)

startLeftAnim();

}

@Override

public void onAnimationEnd(Animation animation) {

}

@Override

public void onAnimationRepeat(Animation animation) {

}

});

}

private void startLeftAnim() {

cradleBallOne.startAnimation(rotateLeftAnimation);

}

private void startRightAnim() {

cradleBallTwo.startAnimation(shakeRightAnimation);

cradleBallThree.startAnimation(shakeRightAnimation);

cradleBallFour.startAnimation(shakeRightAnimation);

}

public void start() {

if (!isStart) {

isStart = true;

startLeftAnim();

}

}

public void stop() {

isStart = false;

cradleBallOne.clearAnimation();

cradleBallTwo.clearAnimation();

cradleBallThree.clearAnimation();

cradleBallFour.clearAnimation();

cradleBallFive.clearAnimation();

}

public boolean isStart() {

return isStart;

}

}

<3>.圆圈转动的动画效果实现

RotateLoading.java的代码实现

public class RotateLoading extends View {

private static final int DEFAULT_WIDTH = 6;

private static final int DEFAULT_SHADOW_POSITION = 2;

private Paint mPaint;

private RectF loadingRectF;

private RectF shadowRectF;

private int topDegree = 10;

private int bottomDegree = 190;

private float arc;

private int width;

private boolean changeBigger = true;

private int shadowPosition;

private boolean isStart = false;

public RotateLoading(Context context) {

super(context);

initView(context, null);

}

public RotateLoading(Context context, AttributeSet attrs) {

super(context, attrs);

initView(context, attrs);

}

public RotateLoading(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView(context, attrs);

}

private void initView(Context context, AttributeSet attrs) {

int color = Color.WHITE;

width = dpToPx(context, DEFAULT_WIDTH);

shadowPosition = dpToPx(getContext(), DEFAULT_SHADOW_POSITION);

if (null != attrs) {

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RotateLoading);

color = typedArray.getColor(R.styleable.RotateLoading_loading_color, Color.WHITE);

width = typedArray.getDimensionPixelSize(R.styleable.RotateLoading_loading_width, dpToPx(context, DEFAULT_WIDTH));

shadowPosition = typedArray.getInt(R.styleable.RotateLoading_shadow_position, DEFAULT_SHADOW_POSITION);

typedArray.recycle();

}

mPaint = new Paint();

mPaint.setColor(color);

mPaint.setAntiAlias(true);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setStrokeWidth(width);

mPaint.setStrokeCap(Paint.Cap.ROUND);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

arc = 10;

loadingRectF = new RectF(2 * width, 2 * width, w - 2 * width, h - 2 * width);

shadowRectF = new RectF(2 * width + shadowPosition, 2 * width + shadowPosition, w - 2 * width + shadowPosition, h - 2 * width + shadowPosition);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (!isStart) {

return;

}

mPaint.setColor(Color.parseColor("#1a000000"));

canvas.drawArc(shadowRectF, topDegree, arc, false, mPaint);

canvas.drawArc(shadowRectF, bottomDegree, arc, false, mPaint);

mPaint.setColor(Color.WHITE);

canvas.drawArc(loadingRectF, topDegree, arc, false, mPaint);

canvas.drawArc(loadingRectF, bottomDegree, arc, false, mPaint);

topDegree += 10;

bottomDegree += 10;

if (topDegree > 360) {

topDegree = topDegree - 360;

}

if (bottomDegree > 360) {

bottomDegree = bottomDegree - 360;

}

if (changeBigger) {

if (arc < 160) {

arc += 2.5;

invalidate();

}

} else {

if (arc > 10) {

arc -= 5;

invalidate();

}

}

if (arc == 160 || arc == 10) {

changeBigger = !changeBigger;

invalidate();

}

}

public void start() {

startAnimator();

isStart = true;

invalidate();

}

public void stop() {

stopAnimator();

invalidate();

}

public boolean isStart() {

return isStart;

}

private void startAnimator() {

ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", 0.0f, 1);

ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 0.0f, 1);

scaleXAnimator.setDuration(300);

scaleXAnimator.setInterpolator(new LinearInterpolator());

scaleYAnimator.setDuration(300);

scaleYAnimator.setInterpolator(new LinearInterpolator());

AnimatorSet animatorSet = new AnimatorSet();

animatorSet.playTogether(scaleXAnimator, scaleYAnimator);

animatorSet.start();

}

private void stopAnimator() {

ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", 1, 0);

ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 1, 0);

scaleXAnimator.setDuration(300);

scaleXAnimator.setInterpolator(new LinearInterpolator());

scaleYAnimator.setDuration(300);

scaleYAnimator.setInterpolator(new LinearInterpolator());

AnimatorSet animatorSet = new AnimatorSet();

animatorSet.playTogether(scaleXAnimator, scaleYAnimator);

animatorSet.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

}

@Override

public void onAnimationEnd(Animator animation) {

isStart = false;

}

@Override

public void onAnimationCancel(Animator animation) {

}

@Override

public void onAnimationRepeat(Animator animation) {

}

});

animatorSet.start();

}

public int dpToPx(Context context, float dpVal) {

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());

}

}

3.需要的资源文件

layout下布局文件

book_loading.xml布局文件实现

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:padding="@dimen/book_padding"

android:background="@color/book_loading_background">

<com.victor.loading.book.BookView

android:layout_width="match_parent"

android:layout_height="match_parent" />

</FrameLayout>

newton_cradle_loading.xml布局文件

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal">

<com.victor.loading.newton.CradleBall

android:id="@+id/ball_one"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_gravity="center"

android:layout_marginLeft="50dp" />

<com.victor.loading.newton.CradleBall

android:id="@+id/ball_two"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_gravity="center" />

<com.victor.loading.newton.CradleBall

android:id="@+id/ball_three"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_gravity="center" />

<com.victor.loading.newton.CradleBall

android:id="@+id/ball_four"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_gravity="center" />

<com.victor.loading.newton.CradleBall

android:id="@+id/ball_five"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_gravity="center"

android:layout_marginRight="50dp" />

</LinearLayout>

values下的资源文件

attrs.xml资源文件

<?xml version="1.0" encoding="utf-8"?>

<resources>

<declare-styleable name="RotateLoading">

<attr name="loading_width" format="dimension"/>

<attr name="loading_color" format="color"/>

<attr name="shadow_position" format="integer"/>

</declare-styleable>

</resources>

color.xml资源文件

<?xml version="1.0" encoding="utf-8"?>

<resources>

<color name="book_loading_background">#ffffff</color>

<color name="book_loading_book">#ff33b5e5</color>

<color name="book_loading_page">#ffffff</color>

</resources>

dimen.xml资源文件

<?xml version="1.0" encoding="utf-8"?>

<resources>

<dimen name="book_border">10dp</dimen>

<dimen name="page_border">5dp</dimen>

<dimen name="book_padding">15dp</dimen>

</resources>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值