1,在网上看了下好看的加载框,看了一下,挺好看的,再看了下源码,就是纯paint画出来的,再加上属性动画就搞定了

再来看一下我们的源码

LvGhost.java

package com.qianmo.retrofitdemo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator; /**
* Created by lumingmin on 16/6/29.
*/ public class LVGhost extends View { float mWidth = 0f;
float mHight = 0f;
Paint mPaint, mPaintHand, mPaintShadow, mPaintArms;
RectF rectFGhost = new RectF();
RectF rectFGhostShadow = new RectF();
float mPadding = 0f;
int mskirtH = 0;
Path path = new Path(); public LVGhost(Context context) {
this(context, null);
} public LVGhost(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public LVGhost(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHight = getMeasuredHeight();
mPadding = 10;
mskirtH = (int) (mWidth / 40);
} private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.WHITE);
mPaintHand = new Paint();
mPaintHand.setAntiAlias(true);
mPaintHand.setStyle(Paint.Style.FILL);
mPaintHand.setColor(Color.argb(220, 0, 0, 0)); mPaintShadow = new Paint();
mPaintShadow.setAntiAlias(true);
mPaintShadow.setStyle(Paint.Style.FILL);
mPaintShadow.setColor(Color.argb(60, 0, 0, 0)); mPaintArms = new Paint();
mPaintArms.setAntiAlias(true);
mPaintArms.setStrokeWidth(8);
mPaintArms.setStyle(Paint.Style.FILL);
mPaintArms.setColor(Color.argb(150, 0, 0, 0)); startAnim();
} private void drawShadow(Canvas canvas) {
canvas.drawArc(rectFGhostShadow, 0, 360, false, mPaintShadow); } private void drawHead(Canvas canvas) {
canvas.drawCircle(rectFGhost.left + rectFGhost.width() / 2
, rectFGhost.width() / 2 + rectFGhost.top
, rectFGhost.width() / 2 - 15
, mPaint
);
} private void drawHand(Canvas canvas) { canvas.drawCircle(rectFGhost.left + rectFGhost.width() / 2 - mskirtH * 3 / 2 + mskirtH * onAnimationRepeatFlag , rectFGhost.width() / 2 + mskirtH + rectFGhost.top,
mskirtH * 0.9f, mPaintHand
);
canvas.drawCircle(rectFGhost.left + rectFGhost.width() / 2 + mskirtH * 3 / 2 + mskirtH * onAnimationRepeatFlag
, rectFGhost.width() / 2 + mskirtH + rectFGhost.top,
mskirtH * 0.9f, mPaintHand
); } float wspace = 10f;
float hspace = 10f; private void drawBody(Canvas canvas) {
path.reset(); float x = (float) ((rectFGhost.width() / 2 - 15) * Math.cos(5 * Math.PI / 180f));
float y = (float) ((rectFGhost.width() / 2 - 15) * Math.sin(5 * Math.PI / 180f)); float x2 = (float) ((rectFGhost.width() / 2 - 15) * Math.cos(175 * Math.PI / 180f));
float y2 = (float) ((rectFGhost.width() / 2 - 15) * Math.sin(175 * Math.PI / 180f)); path.moveTo(rectFGhost.left + rectFGhost.width() / 2 - x, rectFGhost.width() / 2 - y + rectFGhost.top);
path.lineTo(rectFGhost.left + rectFGhost.width() / 2 - x2, rectFGhost.width() / 2 - y2 + rectFGhost.top);
path.quadTo(rectFGhost.right + wspace / 2, rectFGhost.bottom
, rectFGhost.right - wspace, rectFGhost.bottom - hspace); float a = mskirtH;//(mskirtH/2); float m = (rectFGhost.width() - 2 * wspace) / 7f; for (int i = 0; i < 7; i++) {
if (i % 2 == 0) {
path.quadTo(rectFGhost.right - wspace - m * i - (m / 2), rectFGhost.bottom - hspace - a
, rectFGhost.right - wspace - (m * (i + 1)), rectFGhost.bottom - hspace);
} else {
path.quadTo(rectFGhost.right - wspace - m * i - (m / 2), rectFGhost.bottom - hspace + a
, rectFGhost.right - wspace - (m * (i + 1)), rectFGhost.bottom - hspace); }
} path.quadTo(rectFGhost.left - 5, rectFGhost.bottom
, rectFGhost.left + rectFGhost.width() / 2 - x, rectFGhost.width() / 2 - y + rectFGhost.top); path.close();
canvas.drawPath(path, mPaint); }
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save(); float distance = (mWidth - 2 * mPadding) / 3 * 2 * mAnimatedValue; rectFGhost.left = mPadding + distance;
rectFGhost.right = (mWidth - 2 * mPadding) / 3 + distance;
float moveY = 0f;
float moveYMax = mHight / 4f / 2f;
float shadowHighMax = 5f;
float shadowHigh = 0f; if (mAnimatedValue <= 0.25) {
moveY = (float) (moveYMax / 0.25 * mAnimatedValue);
rectFGhost.top = moveY; rectFGhost.bottom = mHight / 4 * 3 + moveY; shadowHigh = shadowHighMax / 0.25f * mAnimatedValue; } else if (mAnimatedValue > 0.25 && mAnimatedValue <= 0.5f) { moveY = (float) (moveYMax / 0.25 * (mAnimatedValue - 0.25f));
rectFGhost.top = moveYMax - moveY;
rectFGhost.bottom = mHight / 4 * 3 + moveYMax - moveY; shadowHigh = shadowHighMax - shadowHighMax / 0.25f * (mAnimatedValue - 0.25f); } else if (mAnimatedValue > 0.5 && mAnimatedValue <= 0.75f) {
moveY = (float) (moveYMax / 0.25 * (mAnimatedValue - 0.5f));
rectFGhost.top = moveY;
rectFGhost.bottom = mHight / 4 * 3 + moveY;
shadowHigh = shadowHighMax / 0.25f * (mAnimatedValue - 0.5f); } else if (mAnimatedValue > 0.75 && mAnimatedValue <= 1f) {
moveY = (float) (moveYMax / 0.25 * (mAnimatedValue - 0.75f));
rectFGhost.top = moveYMax - moveY;
rectFGhost.bottom = mHight / 4 * 3 + moveYMax - moveY;
shadowHigh = shadowHighMax - shadowHighMax / 0.25f * (mAnimatedValue - 0.75f); } rectFGhostShadow.top = mHight - 25 + shadowHigh;
rectFGhostShadow.bottom = mHight - 5 - shadowHigh;
rectFGhostShadow.left = rectFGhost.left + 5 + shadowHigh * 3;
rectFGhostShadow.right = rectFGhost.right - 5 - shadowHigh * 3;
drawShadow(canvas);
drawHead(canvas);
drawBody(canvas);
drawHand(canvas);
canvas.restore(); } public void startAnim() {
stopAnim();
startViewAnim(0f, 1f, 2500);
} private ValueAnimator valueAnimator;
private float mAnimatedValue = 0.f; public void stopAnim() {
if (valueAnimator != null) {
clearAnimation();
valueAnimator.setRepeatCount(0);
valueAnimator.cancel();
valueAnimator.end();
mAnimatedValue = 0f;
wspace = 10;
onAnimationRepeatFlag = 1;
postInvalidate();
}
} int onAnimationRepeatFlag = 1; private ValueAnimator startViewAnim(float startF, final float endF, long time) {
valueAnimator = ValueAnimator.ofFloat(startF, endF);
valueAnimator.setDuration(time);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限循环
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) { mAnimatedValue = (float) valueAnimator.getAnimatedValue(); invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() { @Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
} @Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation); } @Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
onAnimationRepeatFlag = onAnimationRepeatFlag * -1; if (onAnimationRepeatFlag == -1) {
wspace = 22;
} else {
wspace = -2;
} } });
if (!valueAnimator.isRunning()) {
wspace = -2;
valueAnimator.start(); } return valueAnimator;
} }

在我们的布局文件中使用一下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg"
tools:context="com.qianmo.retrofitdemo.MainActivity"> <TextView
android:id="@+id/tv_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="还没有数据"
android:visibility="gone"
/> <Button
android:id="@+id/btn_request"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp"
android:visibility="gone"
android:text="请求网络数据"/> <com.qianmo.retrofitdemo.LVGhost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/loading"
style="@style/loading_style"/>
</RelativeLayout>

这样就可以简单的使用了

  

Android--自定义加载框的更多相关文章

  1. LoaderDialog自定义加载框的实现

    package com.loaderman.loadingdialogdemo; import android.app.Dialog; import android.content.Context; ...

  2. android笔记--加载框

    package com.fuda.ui; import android.app.Activity; import android.os.Bundle; import android.os.Handle ...

  3. Android:webView加载h5网页视频,播放不了,以及横屏全屏的问题和实现自定义加载进度条的效果

    1.webView加载h5网页视频,播放不了,android3.0之后要在menifest添加硬件加速的属性 android:hardwareAccelerated="true". ...

  4. Android图片加载框架最全解析(六),探究Glide的自定义模块功能

    不知不觉中,我们的Glide系列教程已经到了第六篇了,距离第一篇Glide的基本用法发布已经过去了半年的时间.在这半年中,我们通过用法讲解和源码分析配合学习的方式,将Glide的方方面面都研究了个遍, ...

  5. Android 自定义View修炼-自定义加载进度动画XCLoadingImageView

    一.概述 本自定义View,是加载进度动画的自定义View,继承于ImageView来实现,主要实现蒙层加载进度的加载进度效果. 支持水平左右加载和垂直上下加载四个方向,同时也支持自定义蒙层进度颜色. ...

  6. ios新手开发——toast提示和旋转图片加载框

    不知不觉自学ios已经四个月了,从OC语法到app开发,过程虽然枯燥无味,但是结果还是挺有成就感的,在此分享我的ios开发之路中的小小心得~废话不多说,先上我们今天要实现的效果图: 有过一点做APP经 ...

  7. 使用Dialog实现全局Loading加载框

    Dialog实现全局Loading加载框 很多人在实现Loading加载框的时候,都是在当前的页面隐藏一个Loading布局,需要加载的时候,显示出来,加载完再隐藏 使用Dialog实现Loading ...

  8. mui---取消掉默认加载框

    我们在进行打开页面新页面的时候,在APP中会在中间有一个加载框,考虑到用户体验,要取消掉,具体方法是,对openWindow进行配置: 具体参考:http://dev.dcloud.net.cn/mu ...

  9. Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能

    我们的Glide系列文章终于要进入收尾篇了.从我开始写这个系列的第一篇文章时,我就知道这会是一个很长的系列,只是没有想到竟然会写这么久. 在前面的六篇文章中,我们对Glide的方方面面都进行了学习,包 ...

随机推荐

  1. android studio每次启动都要在fetching Android sdk compoment information停好久的解决方案

    1)进入刚安装的Android Studio目录下的bin目录.找到idea.properties文件,用文本编辑器打开.2)在idea.properties文件末尾添加一行: disable.and ...

  2. Linux Kernel Oops异常分析

    1.PowerPC小系统内核异常分析 1.1  异常打印 Unable to handle kernel paging request for data at address 0x36fef31eFa ...

  3. 【BZOJ1503】[HAOI2007]反素数ant 搜索

    结论题...网上讲的好的很多... #include <iostream> using namespace std; ]={,,,,,,,,,},num=; long long ans,n ...

  4. tornado 学习笔记7 RequestHandler功能分析

           在第5部分讲到,构建一个tornado网站,必须包含一个或者多个handler,这些handler是RequestHandler的子类.每个请求都会被映射到handler中进行处理,处理 ...

  5. 转:Maven常用命令

    转:Maven常用命令 Maven库: http://repo2.maven.org/maven2/ Maven依赖查询: http://mvnrepository.com/ Maven常用命令: 1 ...

  6. 《bootstrap》实战---小问题,大Bug

    参照书中代码写了个示例,能够实现大页面单行导航,小页面显示收缩按钮,但是就是不能让收缩按钮发挥作用.也不知道哪儿出了问题. 想想算了,代码也不多,重新来吧.写道导航的时候,突然发现一个<nav& ...

  7. 经典.net面试题目

    1. 简述 private. protected. public. internal 修饰符的访问权限. 答 . private :   私有成员, 在类的内部才可以访问. protected : 保 ...

  8. 畅通工程——D

    D. 畅通工程 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的 ...

  9. Oracle EBS - AOL

    AOL: (Path: /u43/dev6/interface/aol) 1. Goto system administrator response 2. View -> Request (Sa ...

  10. hihoCoder 1183 连通性一·割边与割点(Tarjan求割点与割边)

    #1183 : 连通性一·割边与割点 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 还记得上次小Hi和小Ho学校被黑客攻击的事情么,那一次攻击最后造成了学校网络数据的丢 ...