├── .gitattributes
├── .gitignore
├── Loadings
├── .gitignore
├── LoadingApp
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── zhaoli
│ │ │ └── loadings
│ │ │ ├── LoadingAdapter.java
│ │ │ ├── MainActivity.java
│ │ │ ├── TestActivity.java
│ │ │ ├── interpolator
│ │ │ └── DecelerateAccelerateInterpolator.java
│ │ │ └── loadingViews
│ │ │ ├── AnnulusWhirlLoading.java
│ │ │ ├── BaseLoading.java
│ │ │ ├── ConvertBallLoading.java
│ │ │ ├── DownloadLoading.java
│ │ │ ├── JumpWhirlGraphLoading.java
│ │ │ ├── LineWhirlLoading1.java
│ │ │ ├── LineWhirlLoading2.java
│ │ │ ├── RotateSquareLoading.java
│ │ │ ├── SegmentSquareLoading.java
│ │ │ ├── SwingCollisionLoading.java
│ │ │ ├── TestView.java
│ │ │ └── TranslationBallLoading.java
│ │ └── res
│ │ ├── drawable
│ │ └── loading_item_border.xml
│ │ ├── layout
│ │ ├── loading_item_view.xml
│ │ ├── main_activity.xml
│ │ └── test_item.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ └── strings.xml
├── build.gradle
├── gradle.properties
├── settings.gradle
└── 示例
│ ├── Loading01.gif
│ ├── Loading02.gif
│ ├── Loading03.gif
│ ├── Loading04.gif
│ ├── Loading06.gif
│ ├── Loading07.gif
│ ├── Loading08.gif
│ ├── Loading09.gif
│ ├── Loading10.gif
│ └── Loading11.gif
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
49 |
50 | .gradle
51 | /local.properties
52 | .idea/
53 | .DS_Store
54 | build/
55 | /Loadings/gradlew
56 | /Loadings/gradlew.bat
57 | /Loadings/gradle/wrapper/
--------------------------------------------------------------------------------
/Loadings/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | applicationId "com.zhaoli.loadings"
9 | minSdkVersion 14
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | compile 'com.android.support:recyclerview-v7:22+'
25 | }
26 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\AndroidStudio\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/LoadingAdapter.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.ViewParent;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | /**
14 | * Created by zhaoli on 2016/6/8.
15 | */
16 | public class LoadingAdapter extends RecyclerView.Adapter {
17 |
18 | private Context context = null;
19 | private List loadingViewList = new ArrayList<>();
20 |
21 | public LoadingAdapter(Context context) {
22 | this.context = context;
23 | }
24 |
25 | public void setData(List data) {
26 | loadingViewList.addAll(data);
27 | }
28 |
29 | @Override
30 | public LoadingAdapter.LoadingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
31 | View view = LayoutInflater.from(context).inflate(R.layout.loading_item_view, parent, false);
32 | LoadingViewHolder viewHolder = new LoadingViewHolder(view);
33 | return viewHolder;
34 | }
35 |
36 | @Override
37 | public void onBindViewHolder(LoadingAdapter.LoadingViewHolder holder, int position) {
38 | holder.rootView.removeAllViews();
39 | ViewParent viewParent = loadingViewList.get(position).getParent();
40 | if (viewParent != null) {
41 | if (viewParent instanceof ViewGroup) {
42 | ((ViewGroup) viewParent).removeAllViews();
43 | } else {
44 | return;
45 | }
46 | }
47 | holder.rootView.addView(loadingViewList.get(position));
48 | }
49 |
50 | @Override
51 | public int getItemCount() {
52 | return loadingViewList.size();
53 | }
54 |
55 | public class LoadingViewHolder extends RecyclerView.ViewHolder {
56 |
57 | public ViewGroup rootView = null;
58 |
59 | public LoadingViewHolder(View itemView) {
60 | super(itemView);
61 | rootView = (ViewGroup) itemView;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.View;
8 |
9 | import com.zhaoli.loadings.loadingViews.AnnulusWhirlLoading;
10 | import com.zhaoli.loadings.loadingViews.ConvertBallLoading;
11 | import com.zhaoli.loadings.loadingViews.DownloadLoading;
12 | import com.zhaoli.loadings.loadingViews.JumpWhirlGraphLoading;
13 | import com.zhaoli.loadings.loadingViews.LineWhirlLoading1;
14 | import com.zhaoli.loadings.loadingViews.LineWhirlLoading2;
15 | import com.zhaoli.loadings.loadingViews.TestView;
16 | import com.zhaoli.loadings.loadingViews.TranslationBallLoading;
17 | import com.zhaoli.loadings.loadingViews.RotateSquareLoading;
18 | import com.zhaoli.loadings.loadingViews.SegmentSquareLoading;
19 | import com.zhaoli.loadings.loadingViews.SwingCollisionLoading;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * Created by zhaoli on 2016/6/8.
26 | */
27 | public class MainActivity extends Activity {
28 |
29 | private RecyclerView recyclerView = null;
30 | private LoadingAdapter adapter = null;
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.main_activity);
36 |
37 | recyclerView = (RecyclerView) findViewById(R.id.loadingRecyclerView);
38 | recyclerView.setLayoutManager(new LinearLayoutManager(this));
39 |
40 | adapter = new LoadingAdapter(this);
41 |
42 | List loadingViewList = new ArrayList<>();
43 |
44 | loadingViewList.add(new AnnulusWhirlLoading(this));
45 | loadingViewList.add(new DownloadLoading(this));
46 | loadingViewList.add(new LineWhirlLoading1(this));
47 | loadingViewList.add(new LineWhirlLoading2(this));
48 | loadingViewList.add(new ConvertBallLoading(this));
49 | loadingViewList.add(new JumpWhirlGraphLoading(this));
50 | loadingViewList.add(new TranslationBallLoading(this));
51 | loadingViewList.add(new SegmentSquareLoading(this));
52 | loadingViewList.add(new SwingCollisionLoading(this));
53 | loadingViewList.add(new RotateSquareLoading(this));
54 |
55 | adapter.setData(loadingViewList);
56 | recyclerView.setAdapter(adapter);
57 | adapter.notifyDataSetChanged();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/TestActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | /**
7 | * Created by zhaoli on 2016/6/23.
8 | */
9 | public class TestActivity extends Activity {
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.test_item);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/interpolator/DecelerateAccelerateInterpolator.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.interpolator;
2 |
3 | import android.view.animation.Interpolator;
4 |
5 | /**
6 | * Created by zhaoli on 2016/6/21.
7 | *
8 | * 减速加速
9 | */
10 | public class DecelerateAccelerateInterpolator implements Interpolator {
11 |
12 | public float getInterpolation(float t) {
13 | float x = 2.0f * t - 1.0f;
14 | return 0.5f * ( x * x * x + 1.0f);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/AnnulusWhirlLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Paint;
11 | import android.graphics.RectF;
12 | import android.util.AttributeSet;
13 | import android.view.animation.LinearInterpolator;
14 |
15 | /**
16 | * Created by zhaoli on 2016/6/30.
17 | *
18 | * 环形旋转动画
19 | */
20 | public class AnnulusWhirlLoading extends BaseLoading {
21 |
22 | private final static int BACKGROUND_COLOR = Color.parseColor("#FFFFFF");
23 | private final static int ANNULUS_COLOR_1 = Color.parseColor("#2A343D");
24 | private final static int ANNULUS_COLOR_2 = Color.parseColor("#3DB0EA");
25 | private final static int ANNULUS_COLOR_3 = Color.parseColor("#57B779");
26 | private final static int ANNULUS_COLOR_4 = Color.parseColor("#EC6D63");
27 |
28 | private final static int LINE_WIDTH = 80;
29 | private final static int ANNULUS_RADIUS = 2 * LINE_WIDTH;
30 |
31 | private final static float ANNULUS_LENGTH = (float) (2 * LINE_WIDTH * Math.PI) / 4 / 7;
32 | private final static float ANNULUS_ANGLE_1 = -((float)90 / 14 * 11);
33 | private final static float ANNULUS_ANGLE_2 = -((float)90 / 14 * 7);
34 | private final static float ANNULUS_ANGLE_3 = -((float)90 / 14 * 3);
35 |
36 | private final RectF rectF = new RectF(-ANNULUS_RADIUS, -ANNULUS_RADIUS, ANNULUS_RADIUS, ANNULUS_RADIUS);
37 | //计算区
38 | private float currentAnnulusLeftAngle = 270;
39 | private float currentAnnulusRightAngle = 0;
40 |
41 | private float currentLineWidth = LINE_WIDTH;
42 |
43 | private float currentAnnulusAngle1 = ANNULUS_ANGLE_1;
44 | private float currentAnnulusAngle2 = ANNULUS_ANGLE_2;
45 | private float currentAnnulusAngle3 = ANNULUS_ANGLE_3;
46 |
47 | public AnnulusWhirlLoading(Context context) {
48 | super(context);
49 | initAnim();
50 | }
51 |
52 | public AnnulusWhirlLoading(Context context, AttributeSet attrs) {
53 | super(context, attrs);
54 | initAnim();
55 | }
56 |
57 | public AnnulusWhirlLoading(Context context, AttributeSet attrs, int defStyleAttr) {
58 | super(context, attrs, defStyleAttr);
59 | initAnim();
60 | }
61 |
62 | @Override
63 | protected void onDraw(Canvas canvas) {
64 | super.onDraw(canvas);
65 |
66 | canvas.translate(getWidth() / 2, getHeight() / 2);
67 |
68 | if (currentAnnulusRightAngle > (currentAnnulusAngle1 - (float)90 / 14)) {
69 | drawAnnulus(currentAnnulusAngle1, ANNULUS_COLOR_2, ANNULUS_RADIUS + LINE_WIDTH / 2, canvas);
70 | }
71 | if (currentAnnulusRightAngle > (currentAnnulusAngle2 - (float)90 / 14)) {
72 | drawAnnulus(currentAnnulusAngle2, ANNULUS_COLOR_3, ANNULUS_RADIUS + LINE_WIDTH / 2, canvas);
73 | }
74 | if (currentAnnulusRightAngle > (currentAnnulusAngle3 - (float)90 / 14)) {
75 | drawAnnulus(currentAnnulusAngle3, ANNULUS_COLOR_4, ANNULUS_RADIUS + LINE_WIDTH / 2, canvas);
76 | }
77 |
78 | loadingPaint.setStrokeWidth(LINE_WIDTH);
79 | loadingPaint.setStyle(Paint.Style.STROKE);
80 | loadingPaint.setColor(ANNULUS_COLOR_1);
81 | canvas.drawArc(rectF, currentAnnulusRightAngle, currentAnnulusLeftAngle - currentAnnulusRightAngle, false, loadingPaint);
82 |
83 | //当长度变化的时候 绘制线
84 | if (currentLineWidth < LINE_WIDTH) {
85 | drawAnnulus(0, ANNULUS_COLOR_1, ANNULUS_RADIUS - LINE_WIDTH / 2 + currentLineWidth, canvas);
86 | }
87 | }
88 |
89 | private void drawAnnulus(float currentAngle, int color, float right, Canvas canvas) {
90 | canvas.rotate(currentAngle);
91 | loadingPaint.setStrokeWidth(0);
92 | loadingPaint.setStyle(Paint.Style.FILL);
93 | loadingPaint.setColor(color);
94 | canvas.drawRect(ANNULUS_RADIUS - LINE_WIDTH / 2, -ANNULUS_LENGTH / 2, right, ANNULUS_LENGTH / 2, loadingPaint);
95 | canvas.rotate(-currentAngle);
96 | }
97 |
98 | @Override
99 | protected void initLoading() {
100 | setBackgroundColor(BACKGROUND_COLOR);
101 |
102 | AnimatorSet animatorSet = new AnimatorSet();
103 | Animator closeAnim = getCloseAnim();
104 | Animator openAnim = getOpenAnim();
105 | animatorSet.playSequentially(closeAnim, openAnim);
106 | animatorSet.setInterpolator(new LinearInterpolator());
107 | animatorSet.addListener(new AnimatorListenerAdapter() {
108 | @Override
109 | public void onAnimationEnd(Animator animation) {
110 | super.onAnimationEnd(animation);
111 | animation.start();
112 | }
113 | });
114 | animatorSet.start();
115 | }
116 |
117 | private Animator getCloseAnim() {
118 | AnimatorSet animatorSet = new AnimatorSet();
119 |
120 | ValueAnimator leftAnim = ValueAnimator.ofFloat(270, -90);
121 | leftAnim.setDuration(2000);
122 | //左边弧度的变化
123 | leftAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
124 | @Override
125 | public void onAnimationUpdate(ValueAnimator animation) {
126 | currentAnnulusLeftAngle = (float) animation.getAnimatedValue();
127 | invalidate();
128 | }
129 | });
130 | ValueAnimator rightAnim = ValueAnimator.ofFloat(0, -90);
131 | rightAnim.setDuration(2000);
132 | //右边弧度的变化
133 | rightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
134 | @Override
135 | public void onAnimationUpdate(ValueAnimator animation) {
136 | currentAnnulusRightAngle = (float) animation.getAnimatedValue();
137 | invalidate();
138 | }
139 | });
140 |
141 | animatorSet.playTogether(leftAnim, rightAnim);
142 | animatorSet.setInterpolator(new LinearInterpolator());
143 | return animatorSet;
144 | }
145 |
146 | private Animator getOpenAnim() {
147 | AnimatorSet animatorSet = new AnimatorSet();
148 | ValueAnimator startAnim = ValueAnimator.ofFloat(0, LINE_WIDTH);
149 | startAnim.setDuration(500);
150 | //打开时的起始动画
151 | startAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
152 | @Override
153 | public void onAnimationUpdate(ValueAnimator animation) {
154 | currentLineWidth = (float) animation.getAnimatedValue();
155 | invalidate();
156 | }
157 | });
158 |
159 | ValueAnimator whirlAnim = ValueAnimator.ofFloat(0, 270);
160 | whirlAnim.setDuration(500);
161 | whirlAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
162 | @Override
163 | public void onAnimationUpdate(ValueAnimator animation) {
164 | currentAnnulusLeftAngle = (float) animation.getAnimatedValue();
165 | invalidate();
166 | }
167 | });
168 | whirlAnim.addListener(new AnimatorListenerAdapter() {
169 | @Override
170 | public void onAnimationStart(Animator animation) {
171 | super.onAnimationStart(animation);
172 | currentAnnulusRightAngle = 0;
173 | currentAnnulusAngle1 = Float.MAX_VALUE;
174 | currentAnnulusAngle2 = Float.MAX_VALUE;
175 | currentAnnulusAngle3 = Float.MAX_VALUE;
176 | }
177 | });
178 |
179 | ValueAnimator annulusAnim1 = getAnnulusAnim(360 + ANNULUS_ANGLE_1, 1);
180 | ValueAnimator annulusAnim2 = getAnnulusAnim(360 + ANNULUS_ANGLE_2, 2);
181 | ValueAnimator annulusAnim3 = getAnnulusAnim(360 + ANNULUS_ANGLE_3, 3);
182 |
183 | animatorSet.setInterpolator(new LinearInterpolator());
184 | animatorSet.playSequentially(startAnim, whirlAnim, annulusAnim3, annulusAnim2, annulusAnim1);
185 | return animatorSet;
186 | }
187 |
188 | private ValueAnimator getAnnulusAnim(float endAngle, final int index) {
189 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(270, endAngle);
190 | valueAnimator.setDuration(200);
191 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
192 | @Override
193 | public void onAnimationUpdate(ValueAnimator animation) {
194 | if (index == 1) {
195 | currentAnnulusAngle1 = (float) animation.getAnimatedValue() - 360;
196 | } else if (index == 2) {
197 | currentAnnulusAngle2 = (float) animation.getAnimatedValue() - 360;
198 | } else if (index == 3) {
199 | currentAnnulusAngle3 = (float) animation.getAnimatedValue() - 360;
200 | }
201 | invalidate();
202 | }
203 | });
204 | return valueAnimator;
205 | }
206 |
207 | @Override
208 | protected void initLoadingPaint() {
209 | loadingPaint.setAntiAlias(true);
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/BaseLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.content.Context;
6 | import android.graphics.Paint;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 |
10 | /**
11 | * Created by zhaoli on 2016/6/17.
12 | */
13 | public abstract class BaseLoading extends View {
14 |
15 | protected Context context = null;
16 | protected Paint loadingPaint = new Paint();
17 |
18 | public BaseLoading(Context context) {
19 | super(context);
20 | this.context = context;
21 | }
22 |
23 | public BaseLoading(Context context, AttributeSet attrs) {
24 | super(context, attrs);
25 | this.context = context;
26 | }
27 |
28 | public BaseLoading(Context context, AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | this.context = context;
31 | }
32 |
33 | /**
34 | * 重载必须调用 (构造结束后调用)
35 | */
36 | protected void initAnim() {
37 | initLoadingPaint();
38 | initLoading();
39 | }
40 |
41 | protected abstract void initLoading();
42 | protected abstract void initLoadingPaint();
43 | }
44 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/ConvertBallLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.AnimatorSet;
4 | import android.animation.ValueAnimator;
5 | import android.content.Context;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.util.AttributeSet;
9 | import android.view.animation.LinearInterpolator;
10 |
11 | /**
12 | * Created by zhaoli on 2016/6/21.
13 | * 变换球体加载
14 | */
15 | public class ConvertBallLoading extends BaseLoading {
16 |
17 | private final static int BALL_RADIUS = 20;
18 |
19 | private final static int[] BALL_COLOR = new int[] {
20 | Color.parseColor("#3E8EFF"), //蓝
21 | Color.parseColor("#FF4B4B"), //红
22 | Color.parseColor("#FFD91E") //黄
23 | };
24 |
25 | private final static int BACK_GROUND = Color.parseColor("#FBF8F0");
26 |
27 | //left
28 | private int[] offset_radius;
29 | private int[] offset;
30 | private int leftStep = 0;//步骤 0, 1, 2, 3
31 |
32 | //right
33 | private int[] center; //中心点(1:左 2:右)
34 | private int[] whirl_radius;
35 | private final static int BALL_RADIUS_2 = 2 * BALL_RADIUS;
36 | private final static int BALL_RADIUS_3 = 3 * BALL_RADIUS;
37 |
38 |
39 | public ConvertBallLoading(Context context) {
40 | super(context);
41 | initAnim();
42 | }
43 |
44 | public ConvertBallLoading(Context context, AttributeSet attrs) {
45 | super(context, attrs);
46 | initAnim();
47 | }
48 |
49 | public ConvertBallLoading(Context context, AttributeSet attrs, int defStyleAttr) {
50 | super(context, attrs, defStyleAttr);
51 | initAnim();
52 | }
53 |
54 | @Override
55 | protected void onDraw(Canvas canvas) {
56 | super.onDraw(canvas);
57 |
58 | //绘制第一幅
59 | if (leftStep == 0) {
60 | drawLeft(2, 0, 1, canvas); //0-1交1 0-2重1
61 | } else if (leftStep == 1) {
62 | drawLeft(1, 2, 0, canvas); //1-2交2
63 | } else if (leftStep == 2) {
64 | drawLeft(2, 0, 1, canvas); //0-1交1 0-2重0
65 | } else {
66 | drawLeft(1, 2, 0, canvas); //1-2交2
67 | }
68 |
69 | //绘制第二幅
70 | canvas.translate(getWidth() / 2, 0);
71 | drawRight(0, canvas);
72 | drawRight(1, canvas);
73 | drawRight(2, canvas);
74 | }
75 |
76 | private void drawLeft(int i, int j, int k, Canvas canvas) {
77 | canvas.translate(getWidth() / 4, getHeight() / 2);
78 | loadingPaint.setColor(BALL_COLOR[i]);
79 | canvas.drawCircle(offset[i], 0, BALL_RADIUS + offset_radius[i], loadingPaint);
80 |
81 | loadingPaint.setColor(BALL_COLOR[j]);
82 | canvas.drawCircle(offset[j], 0, BALL_RADIUS + offset_radius[j], loadingPaint);
83 |
84 | loadingPaint.setColor(BALL_COLOR[k]);
85 | canvas.drawCircle(offset[k], 0, BALL_RADIUS + offset_radius[k], loadingPaint);
86 | }
87 |
88 | private void drawRight(int index, Canvas canvas) {
89 |
90 | float x, y;
91 |
92 | if (whirl_radius[index] >= 0 && whirl_radius[index] < 90) {
93 | y = -BALL_RADIUS_3 * sin(whirl_radius[index]);
94 | } else if (whirl_radius[index] >= 90 && whirl_radius[index] < 180) {
95 | y = -BALL_RADIUS_3 * sin(180 - whirl_radius[index]);
96 | } else if (whirl_radius[index] >= 180 && whirl_radius[index] < 270) {
97 | y = BALL_RADIUS_3 * cos(270 - whirl_radius[index]);
98 | } else {
99 | y = BALL_RADIUS_3 * sin(360 - whirl_radius[index]);
100 | }
101 |
102 | if (whirl_radius[index] >= 0 && whirl_radius[index] < 90) {
103 | x = (center[index] == 1) ? (-BALL_RADIUS_2 - BALL_RADIUS_2 * cos(whirl_radius[index])) :
104 | (BALL_RADIUS_2 - BALL_RADIUS_2 * cos(whirl_radius[index]));
105 | } else if (whirl_radius[index] >= 90 && whirl_radius[index] < 180) {
106 | x = (center[index] == 1) ? (-BALL_RADIUS_2 + BALL_RADIUS_2 * cos(180 - whirl_radius[index])) :
107 | (BALL_RADIUS_2 + BALL_RADIUS_2 * cos(180 - whirl_radius[index]));
108 | } else if (whirl_radius[index] >= 180 && whirl_radius[index] < 270) {
109 | x = (center[index] == 1) ? (-BALL_RADIUS_2 + BALL_RADIUS_2 * sin(270 - whirl_radius[index])) :
110 | (BALL_RADIUS_2 + BALL_RADIUS_2 * sin(270 - whirl_radius[index]));
111 | } else {
112 | x = (center[index] == 1) ? (-BALL_RADIUS_2 - BALL_RADIUS_2 * cos(360 - whirl_radius[index])) :
113 | (BALL_RADIUS_2 - BALL_RADIUS_2 * cos(360 - whirl_radius[index]));
114 | }
115 |
116 | loadingPaint.setColor(BALL_COLOR[index]);
117 | canvas.drawCircle(x, y, BALL_RADIUS, loadingPaint);
118 | }
119 |
120 | private float sin(int angle) {
121 | return (float) Math.sin(Math.toRadians(angle));
122 | }
123 |
124 | private float cos(int angle) {
125 | return (float) Math.cos(Math.toRadians(angle));
126 | }
127 |
128 | @Override
129 | protected void initLoading() {
130 | setBackgroundColor(BACK_GROUND);
131 |
132 | AnimatorSet animatorSet = new AnimatorSet();
133 |
134 | offset = new int[3];
135 | offset_radius = new int[3];
136 | ValueAnimator leftMoveAnim = getLeftMoveAnim();
137 |
138 | center = new int[3];
139 | whirl_radius = new int[3];
140 | ValueAnimator rightAnim = getRightAnim();
141 |
142 | animatorSet.playTogether(leftMoveAnim, rightAnim);
143 | animatorSet.start();
144 | }
145 |
146 | private ValueAnimator getLeftMoveAnim() {
147 | ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 6 * BALL_RADIUS, 12 * BALL_RADIUS,
148 | 18 * BALL_RADIUS, 24 * BALL_RADIUS);
149 | valueAnimator.setDuration(2000);
150 | valueAnimator.setRepeatCount(-1);
151 | valueAnimator.setInterpolator(new LinearInterpolator());
152 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
153 | @Override
154 | public void onAnimationUpdate(ValueAnimator animation) {
155 | int value = (int) animation.getAnimatedValue();
156 | if (value >= 0 && value < 6 * BALL_RADIUS) {
157 | offset[0] = value - 6 * BALL_RADIUS;
158 | offset[1] = -value;
159 | offset[2] = 6 * BALL_RADIUS - value;
160 |
161 | offset_radius[0] = offset_radius[2] = value / 6; //[0, 0.5]
162 | offset_radius[1] = BALL_RADIUS - value / 6; //[0.5, 0]
163 |
164 | leftStep = 0;
165 | } else if (value >= 6 * BALL_RADIUS && value < 12 * BALL_RADIUS) {
166 | offset[0] = value - 6 * BALL_RADIUS;
167 | offset[1] = -(12 * BALL_RADIUS - value);
168 | offset[2] = 6 * BALL_RADIUS - value;
169 |
170 | offset_radius[0] = offset_radius[2] = BALL_RADIUS - (value - 6 * BALL_RADIUS) / 6; //[0.5, 0]
171 | offset_radius[1] = (value - 6 * BALL_RADIUS) / 6; //[0, 0.5]
172 |
173 | leftStep = 1;
174 | } else if (value >= 12 * BALL_RADIUS && value < 18 * BALL_RADIUS) {
175 | offset[0] = 18 * BALL_RADIUS - value;
176 | offset[1] = value - 12 * BALL_RADIUS;
177 | offset[2] = -(18 * BALL_RADIUS - value);
178 |
179 | offset_radius[0] = offset_radius[2] = (value - 12 * BALL_RADIUS) / 6; //[0, 0.5]
180 | offset_radius[1] = BALL_RADIUS - (value - 12 * BALL_RADIUS) / 6; //[0.5, 0]
181 |
182 | leftStep = 2;
183 | } else if (value >= 18 * BALL_RADIUS && value < 24 * BALL_RADIUS) {
184 | offset[0] = -(value - 18 * BALL_RADIUS);
185 | offset[1] = 24 * BALL_RADIUS - value;
186 | offset[2] = value - 18 * BALL_RADIUS;
187 |
188 | offset_radius[0] = offset_radius[2] = BALL_RADIUS - (value - 18 * BALL_RADIUS) / 6; //[0.5, 0]
189 | offset_radius[1] = (value - 18 * BALL_RADIUS) / 6; //[0, 0.5]
190 |
191 | leftStep = 3;
192 | }
193 | invalidate();
194 | }
195 | });
196 | return valueAnimator;
197 | }
198 |
199 | private ValueAnimator getRightAnim() {
200 | ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 90, 180, 270, 360, 450, 540, 630, 720);
201 | valueAnimator.setDuration(1500);
202 | valueAnimator.setRepeatCount(-1);
203 | valueAnimator.setInterpolator(new LinearInterpolator());
204 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
205 | @Override
206 | public void onAnimationUpdate(ValueAnimator animation) {
207 | int value = (int) animation.getAnimatedValue();
208 | //计算每个
209 | if (value >= 90 && value < 450) {
210 | center[0] = 2;
211 | whirl_radius[0] = value - 90;
212 | } else {
213 | center[0] = 1;
214 | if (value >= 450 && value < 630) {
215 | whirl_radius[0] = 180 - (value - 450);
216 | } else if (value >= 0 && value < 90) {
217 | whirl_radius[0] = 270 - value;
218 | } else {
219 | whirl_radius[0] = 360 - (value - 630);
220 | }
221 | }
222 |
223 | if (value >= 0 && value < 360) {
224 | center[1] = 1;
225 | if (value >= 0 && value < 180) {
226 | whirl_radius[1] = 180 - value;
227 | } else {
228 | whirl_radius[1] = 360 - (value - 180);
229 | }
230 | } else {
231 | center[1] = 2;
232 | whirl_radius[1] = value - 360;
233 | }
234 |
235 | if (value >= 0 && value < 270) {
236 | center[2] = 2;
237 | whirl_radius[2] = 90 + value;
238 | } else if (value >= 270 && value < 630) {
239 | center[2] = 1;
240 | if (value >= 270 && value < 450) {
241 | whirl_radius[2] = 180 - (value - 270);
242 | } else {
243 | whirl_radius[2] = 360 - (value - 450);
244 | }
245 | } else {
246 | center[2] = 2;
247 | whirl_radius[2] = value - 630;
248 | }
249 | }
250 | });
251 | return valueAnimator;
252 | }
253 |
254 | @Override
255 | protected void initLoadingPaint() {
256 | loadingPaint.setAntiAlias(true);
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/DownloadLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Paint;
11 | import android.graphics.Path;
12 | import android.graphics.RectF;
13 | import android.util.AttributeSet;
14 | import android.view.animation.AccelerateInterpolator;
15 | import android.view.animation.LinearInterpolator;
16 |
17 | import com.zhaoli.loadings.interpolator.DecelerateAccelerateInterpolator;
18 |
19 | /**
20 | * Created by zhaoli on 2016/6/22.
21 | * 下载加载动画
22 | */
23 | public class DownloadLoading extends BaseLoading {
24 | private final static int BACK_GROUND_COLOR = Color.parseColor("#1C9CF2");
25 | private final static int UN_DO_LINE_COLOR = Color.parseColor("#2FA4F2");
26 | private final static int DO_LINE_COLOR = Color.parseColor("#FFFFFF");
27 |
28 | private final static int CIRCULAR_RADIUS = 150;
29 | private final static int CIRCULAR_WIDTH = 12;
30 |
31 | private final static float P_CIRCULAR = (float) (2 * Math.PI * CIRCULAR_RADIUS);
32 | private final static RectF RECTF = new RectF(-CIRCULAR_RADIUS, -CIRCULAR_RADIUS, CIRCULAR_RADIUS, CIRCULAR_RADIUS);
33 |
34 | private final static float ARROW_LENGTH = (float) (CIRCULAR_RADIUS / 2 / Math.cos(Math.toRadians(45)));//箭头长度
35 | private final static float CENTER_TEXT_SIZE = 36; //中心文字大小
36 |
37 |
38 | private final static float WAVE_MAX = 4; //波浪数量
39 | private final static float WAVE_RADIUS = ARROW_LENGTH / (2 * WAVE_MAX); //波浪半径
40 |
41 | //-----数据区
42 | private final static int PROGRESS_MAX = 100;
43 |
44 | private int currentProgress = 0;
45 | private int maxProgress = PROGRESS_MAX;
46 |
47 | private String centerText = "";
48 |
49 | //-----动画区
50 | private int currentLineLength = CIRCULAR_RADIUS; //当前线条长度
51 | private int currentLineAngle = 90; //当前箭头夹角
52 | private int currentLineHeight = 0; //当前线条高度
53 |
54 | private float currentTextSize = 0; //当前文字大小
55 | private float currentWavePosition = ARROW_LENGTH; //当前波浪位置
56 | private float currentWaveOffset = 0; //当前波浪偏移
57 | private RectF waveBeginRectF = new RectF();
58 |
59 | //对勾两个点的Y变化
60 | private float currentArrowMidHeight = 0;
61 | private float currentArrowEndHeight = 0;
62 |
63 | private ValueAnimator waveAnim; //波浪动画
64 |
65 | private int animState = -1; //0 开始动画 1 中间动画 2 结束动画
66 |
67 | private Path path = new Path();
68 |
69 | public DownloadLoading(Context context) {
70 | super(context);
71 | initAnim();
72 | }
73 |
74 | public DownloadLoading(Context context, AttributeSet attrs) {
75 | super(context, attrs);
76 | initAnim();
77 | }
78 |
79 | public DownloadLoading(Context context, AttributeSet attrs, int defStyleAttr) {
80 | super(context, attrs, defStyleAttr);
81 | initAnim();
82 | }
83 |
84 | public void setCurrentProgress(int currentProgress) {
85 | this.currentProgress = currentProgress;
86 | centerText = "" + currentProgress;
87 | if (currentProgress >= maxProgress) {
88 | onLoadingEnd();
89 | onStartAnimEnd();
90 | }
91 | }
92 |
93 | @Override
94 | protected void onDraw(Canvas canvas) {
95 | super.onDraw(canvas);
96 |
97 | canvas.translate(getWidth() / 2, getHeight() / 2);
98 |
99 | //绘制初始圈
100 | loadingPaint.setColor(UN_DO_LINE_COLOR);
101 | canvas.drawCircle(0, 0, CIRCULAR_RADIUS, loadingPaint);
102 |
103 | //绘制进度
104 | canvas.rotate(-90);
105 | float angle = ((float) currentProgress / maxProgress) * 360;
106 | loadingPaint.setColor(DO_LINE_COLOR);
107 | canvas.drawArc(RECTF, 0, -angle, true, loadingPaint);
108 |
109 | //绘制中心圈
110 | loadingPaint.setColor(BACK_GROUND_COLOR);
111 | canvas.drawCircle(0, 0, CIRCULAR_RADIUS - CIRCULAR_WIDTH, loadingPaint);
112 |
113 | if (animState == 0) {
114 | drawStart(canvas);
115 | } else if (animState == 1) {
116 | drawLoading(canvas);
117 | } else {
118 | drawEnd(canvas);
119 | }
120 |
121 | loadingPaint.setStyle(Paint.Style.FILL);
122 | }
123 |
124 | private void drawStart(Canvas canvas) {
125 | //绘制开始动画
126 | //1.绘制竖线
127 | loadingPaint.setColor(DO_LINE_COLOR);
128 |
129 | //复原画布
130 | canvas.rotate(90);
131 | loadingPaint.setStrokeWidth(CIRCULAR_WIDTH);
132 | canvas.drawLine(0, -currentLineLength / 2 - currentLineHeight, 0, currentLineLength / 2 - currentLineHeight, loadingPaint);
133 | //2.绘制箭头
134 | loadingPaint.setStrokeWidth(CIRCULAR_WIDTH / 2);
135 | float lineX = (float) (-ARROW_LENGTH * Math.sin(Math.toRadians(currentLineAngle / 2)));
136 | float lineY = (float) (ARROW_LENGTH * Math.cos(Math.toRadians(currentLineAngle / 2))) + CIRCULAR_WIDTH / 2;
137 | canvas.drawLine(lineX, CIRCULAR_WIDTH / 2, 0, lineY, loadingPaint);
138 | canvas.drawLine(0, lineY, -lineX, CIRCULAR_WIDTH / 2, loadingPaint);
139 | }
140 |
141 | private void drawLoading(Canvas canvas) {
142 | //绘制中间动画
143 | //1. 绘制文字
144 |
145 | //复原画布
146 | canvas.rotate(90);
147 | loadingPaint.setColor(DO_LINE_COLOR);
148 | if (currentTextSize > 0) {
149 | loadingPaint.setTextSize(currentTextSize);
150 | loadingPaint.setTextAlign(Paint.Align.CENTER);
151 | canvas.drawText(centerText, 0, CIRCULAR_RADIUS / 2, loadingPaint);
152 | }
153 |
154 | //2. 绘制波浪
155 | canvas.translate(-ARROW_LENGTH, 0);
156 | //水平线
157 | path.reset();
158 | path.moveTo(0, 0);
159 | path.lineTo(currentWavePosition, 0);
160 |
161 | if (currentWaveOffset > 0) {
162 | path.reset();
163 | float waveBeginAngle; //波浪开始部分的角度
164 | float waveBeginRadius = WAVE_RADIUS * 2 / 3; //波浪开始部分的半径
165 | if (currentWaveOffset > 0 && currentWaveOffset <= WAVE_RADIUS) {
166 | waveBeginAngle = (float) Math.toDegrees(Math.acos((WAVE_RADIUS - currentWaveOffset) / WAVE_RADIUS));
167 | waveBeginRectF.set(-currentWaveOffset, -waveBeginRadius, 2 * WAVE_RADIUS - currentWaveOffset, waveBeginRadius);
168 | path.addArc(waveBeginRectF, 180 + waveBeginAngle, 180 - waveBeginAngle);
169 | waveBeginRectF.set(waveBeginRectF.right, waveBeginRectF.top, waveBeginRectF.right + 2 * WAVE_RADIUS, waveBeginRectF.bottom);
170 | path.addArc(waveBeginRectF, 0, 180);
171 | } else if (currentWaveOffset > WAVE_RADIUS && currentWaveOffset <= 2 * WAVE_RADIUS) {
172 | waveBeginAngle = (float) (180 - Math.toDegrees(Math.acos((currentWaveOffset - WAVE_RADIUS) / WAVE_RADIUS)));
173 | waveBeginRectF.set(-currentWaveOffset, -waveBeginRadius, 2 * WAVE_RADIUS - currentWaveOffset, waveBeginRadius);
174 | path.addArc(waveBeginRectF, 180 + waveBeginAngle, 180 - waveBeginAngle);
175 | waveBeginRectF.set(waveBeginRectF.right, waveBeginRectF.top, waveBeginRectF.right + 2 * WAVE_RADIUS, waveBeginRectF.bottom);
176 | path.addArc(waveBeginRectF, 0, 180);
177 | } else if (currentWaveOffset > 2 * WAVE_RADIUS && currentWaveOffset <= 3 * WAVE_RADIUS) {
178 | waveBeginAngle = (float) Math.toDegrees(Math.acos((3 * WAVE_RADIUS - currentWaveOffset) / WAVE_RADIUS));
179 | waveBeginRectF.set(-currentWaveOffset + 2 * WAVE_RADIUS, -waveBeginRadius, 4 * WAVE_RADIUS - currentWaveOffset, waveBeginRadius);
180 | path.addArc(waveBeginRectF, 0, 180 - waveBeginAngle);
181 | } else {
182 | waveBeginAngle = (float) (180 - Math.toDegrees(Math.acos((currentWaveOffset - 3 * WAVE_RADIUS) / WAVE_RADIUS)));
183 | waveBeginRectF.set(-currentWaveOffset + 2 * WAVE_RADIUS, -waveBeginRadius, 4 * WAVE_RADIUS - currentWaveOffset, waveBeginRadius);
184 | path.addArc(waveBeginRectF, 0, 180 - waveBeginAngle);
185 | }
186 | path.moveTo(waveBeginRectF.right, 0);
187 | }
188 |
189 | float laveLength = 2 * ARROW_LENGTH - currentWavePosition - (4 * WAVE_RADIUS - currentWaveOffset);
190 | while (laveLength >= 4 * WAVE_RADIUS) {
191 | path.rQuadTo(WAVE_RADIUS, -WAVE_RADIUS, 2 * WAVE_RADIUS, 0);
192 | path.rQuadTo(WAVE_RADIUS, WAVE_RADIUS, 2 * WAVE_RADIUS, 0);
193 | laveLength -= 4 * WAVE_RADIUS;
194 | }
195 |
196 | if (laveLength >= 2 * WAVE_RADIUS) {
197 | path.rQuadTo(WAVE_RADIUS, -WAVE_RADIUS, 2 * WAVE_RADIUS, 0);
198 | laveLength -= 2 * WAVE_RADIUS;
199 | path.rQuadTo(WAVE_RADIUS, WAVE_RADIUS, laveLength, 0);
200 | }
201 |
202 | loadingPaint.setStyle(Paint.Style.STROKE);
203 | canvas.drawPath(path, loadingPaint);
204 | }
205 |
206 | private void drawEnd(Canvas canvas) {
207 | //绘制结束动画
208 |
209 | //复原画布
210 | canvas.rotate(90);
211 | loadingPaint.setColor(DO_LINE_COLOR);
212 | if (currentTextSize > 0) {
213 | loadingPaint.setTextSize(currentTextSize);
214 | loadingPaint.setTextAlign(Paint.Align.CENTER);
215 | canvas.drawText(centerText, 0, CIRCULAR_RADIUS / 2, loadingPaint);
216 | }
217 |
218 | //2. 绘制直线
219 | path.reset();
220 | float startX, startY, midX, midY, endX, endY;
221 |
222 | midX = -(float) (ARROW_LENGTH / 3 - currentArrowMidHeight / Math.tan(Math.toRadians(ARROW_MID_ANGLE)));
223 | midY = currentArrowMidHeight;
224 |
225 | startX = -(float) (Math.sqrt((ARROW_LENGTH * 2 / 3) * (ARROW_LENGTH * 2 / 3) - currentArrowMidHeight * currentArrowMidHeight)) + midX;
226 | startY = 0;
227 |
228 | endX = (float) (ARROW_LENGTH - currentArrowEndHeight / Math.tan(Math.toRadians(ARROW_END_ANGLE)));
229 | endY = -currentArrowEndHeight;
230 |
231 | path.moveTo(startX, startY);
232 | path.lineTo(midX, midY);
233 | path.lineTo(endX, endY);
234 | loadingPaint.setStyle(Paint.Style.STROKE);
235 | loadingPaint.setStrokeWidth(CIRCULAR_WIDTH / 2);
236 | canvas.drawPath(path, loadingPaint);
237 | }
238 |
239 | @Override
240 | protected void initLoading() {
241 | setBackgroundColor(BACK_GROUND_COLOR);
242 |
243 | startStartAnim();
244 | }
245 |
246 | @Override
247 | protected void initLoadingPaint() {
248 | loadingPaint.setAntiAlias(true);
249 | }
250 |
251 | private AnimatorSet getDownloadStartAnim() {
252 | AnimatorSet animatorSet = new AnimatorSet();
253 | AnimatorSet animatorSet1 = new AnimatorSet();
254 | AnimatorSet animatorSet2 = new AnimatorSet();
255 |
256 | ValueAnimator valueAnimator1 = ValueAnimator.ofInt(CIRCULAR_RADIUS, CIRCULAR_WIDTH);
257 | valueAnimator1.setInterpolator(new AccelerateInterpolator());
258 | valueAnimator1.setDuration(500);
259 | valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
260 | @Override
261 | public void onAnimationUpdate(ValueAnimator animation) {
262 | currentLineLength = (int) animation.getAnimatedValue();
263 | animState = 0;
264 | invalidate();
265 | }
266 | });
267 |
268 | ValueAnimator valueAnimator2 = ValueAnimator.ofInt(90, 180);
269 | valueAnimator2.setInterpolator(new AccelerateInterpolator());
270 | valueAnimator2.setDuration(500);
271 | valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
272 | @Override
273 | public void onAnimationUpdate(ValueAnimator animation) {
274 | currentLineAngle = (int) animation.getAnimatedValue();
275 | animState = 0;
276 | invalidate();
277 | }
278 | });
279 |
280 | ValueAnimator valueAnimator3 = ValueAnimator.ofInt(0, CIRCULAR_RADIUS + CIRCULAR_WIDTH, CIRCULAR_WIDTH);
281 | valueAnimator3.setDuration(500);
282 | valueAnimator3.setInterpolator(new DecelerateAccelerateInterpolator());
283 | valueAnimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
284 | @Override
285 | public void onAnimationUpdate(ValueAnimator animation) {
286 | currentLineHeight = (int) animation.getAnimatedValue();
287 | animState = 0;
288 | invalidate();
289 | }
290 | });
291 |
292 | ValueAnimator valueAnimator4 = ValueAnimator.ofInt(180, 190, 170, 180);
293 | valueAnimator4.setDuration(500);
294 | valueAnimator4.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
295 | @Override
296 | public void onAnimationUpdate(ValueAnimator animation) {
297 | currentLineAngle = (int) animation.getAnimatedValue();
298 | animState = 0;
299 | invalidate();
300 | }
301 | });
302 |
303 | animatorSet1.playTogether(valueAnimator1, valueAnimator2);
304 | animatorSet2.playTogether(valueAnimator3, valueAnimator4);
305 | animatorSet.playSequentially(animatorSet1, animatorSet2);
306 | return animatorSet;
307 | }
308 |
309 | private AnimatorSet getDownloadingAnim() {
310 | AnimatorSet animatorSet = new AnimatorSet();
311 |
312 | AnimatorSet animatorSet1 = new AnimatorSet();
313 |
314 | ValueAnimator textSizeAnim = ValueAnimator.ofFloat(0, CENTER_TEXT_SIZE);
315 | textSizeAnim.setDuration(500);
316 | textSizeAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
317 | @Override
318 | public void onAnimationUpdate(ValueAnimator animation) {
319 | currentTextSize = (float) animation.getAnimatedValue();
320 | animState = 1;
321 | invalidate();
322 | }
323 | });
324 |
325 | ValueAnimator lineAnim = ValueAnimator.ofFloat(2 * ARROW_LENGTH, 0);
326 | lineAnim.setDuration(500);
327 | lineAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
328 | @Override
329 | public void onAnimationUpdate(ValueAnimator animation) {
330 | currentWavePosition = (float) animation.getAnimatedValue();
331 | animState = 1;
332 | invalidate();
333 | }
334 | });
335 |
336 | animatorSet1.playTogether(textSizeAnim, lineAnim);
337 |
338 | waveAnim = ValueAnimator.ofFloat(0, 4 * WAVE_RADIUS);
339 | waveAnim.setDuration(300);
340 | waveAnim.setRepeatCount(-1);
341 | waveAnim.setInterpolator(new LinearInterpolator());
342 | waveAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
343 | @Override
344 | public void onAnimationUpdate(ValueAnimator animation) {
345 | currentWaveOffset = (float) animation.getAnimatedValue();
346 | animState = 1;
347 | invalidate();
348 | }
349 | });
350 |
351 | animatorSet.playSequentially(animatorSet1, waveAnim);
352 |
353 | return animatorSet;
354 | }
355 |
356 | private final static float ARROW_MID_Y_MAX = (float) (ARROW_LENGTH * 2 / 3 * Math.cos(Math.toRadians(45))); // 最终30度
357 | private final static float ARROW_END_Y_MAX = -(float) (ARROW_LENGTH * 4 / 3 * Math.cos(Math.toRadians(30)) - ARROW_MID_Y_MAX);
358 | private final static float ARROW_END_X_MAX = (float) (ARROW_LENGTH * 4 / 3 * Math.sin(Math.toRadians(30)));
359 | private final static float ARROW_MID_ANGLE = (float) Math.toDegrees(Math.atan(ARROW_MID_Y_MAX / (ARROW_LENGTH / 3)));
360 | private final static float ARROW_END_ANGLE = (float) Math.toDegrees(Math.atan(-ARROW_END_Y_MAX / (ARROW_LENGTH - ARROW_END_X_MAX)));
361 | private AnimatorSet getDownloadEndAnim() {
362 | AnimatorSet animatorSet = new AnimatorSet();
363 |
364 | ValueAnimator textSizeAnim = ValueAnimator.ofFloat(CENTER_TEXT_SIZE, 0);
365 | textSizeAnim.setDuration(500);
366 | textSizeAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
367 | @Override
368 | public void onAnimationUpdate(ValueAnimator animation) {
369 | currentTextSize = (float) animation.getAnimatedValue();
370 | animState = 2;
371 | invalidate();
372 | }
373 | });
374 |
375 | AnimatorSet animatorSet1 = new AnimatorSet();
376 | ValueAnimator arrowAnim1 = ValueAnimator.ofFloat(0, ARROW_MID_Y_MAX);
377 | arrowAnim1.setDuration(1000);
378 | arrowAnim1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
379 | @Override
380 | public void onAnimationUpdate(ValueAnimator animation) {
381 | currentArrowMidHeight = (float) animation.getAnimatedValue();
382 | animState = 2;
383 | invalidate();
384 | }
385 | });
386 |
387 | ValueAnimator arrowAnim2 = ValueAnimator.ofFloat(0, -ARROW_END_Y_MAX);
388 | arrowAnim2.setDuration(1000);
389 | arrowAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
390 | @Override
391 | public void onAnimationUpdate(ValueAnimator animation) {
392 | currentArrowEndHeight = (float) animation.getAnimatedValue();
393 | animState = 2;
394 | invalidate();
395 | }
396 | });
397 |
398 | animatorSet1.playTogether(arrowAnim1, arrowAnim2);
399 |
400 | animatorSet.playSequentially(textSizeAnim, animatorSet1);
401 |
402 | return animatorSet;
403 | }
404 |
405 | /**
406 | * 进度测试
407 | * @return
408 | */
409 | public DownloadLoading test() {
410 | new Thread(new Runnable() {
411 | @Override
412 | public void run() {
413 | currentProgress = 0;
414 | while (true) {
415 | post(new Runnable() {
416 | @Override
417 | public void run() {
418 | setCurrentProgress(++currentProgress);
419 | }
420 | });
421 | post(new Runnable() {
422 | @Override
423 | public void run() {
424 | invalidate();
425 | }
426 | });
427 | try {
428 | Thread.sleep(100);
429 | } catch (Exception e) {
430 | e.printStackTrace();
431 | }
432 | }
433 | }
434 | }).start();
435 | return this;
436 | }
437 |
438 | /**
439 | * 启动加载中动画
440 | */
441 | private void startLoadingAnim() {
442 | AnimatorSet animatorSet = getDownloadingAnim();
443 | animatorSet.start();
444 | }
445 |
446 | /**
447 | * 启动开始动画
448 | */
449 | private void startStartAnim() {
450 | AnimatorSet animatorSet = getDownloadStartAnim();
451 | animatorSet.addListener(new AnimatorListenerAdapter() {
452 | @Override
453 | public void onAnimationEnd(Animator animation) {
454 | super.onAnimationEnd(animation);
455 | animState = -1;
456 | onStartAnimEnd();
457 | startLoadingAnim();
458 | }
459 | });
460 | animatorSet.start();
461 | }
462 |
463 | private void startEndAnim() {
464 | waveAnim.cancel();
465 | AnimatorSet animatorSet = getDownloadEndAnim();
466 | animatorSet.addListener(new AnimatorListenerAdapter() {
467 | @Override
468 | public void onAnimationEnd(Animator animation) {
469 | super.onAnimationEnd(animation);
470 | animState = -1;
471 | onEndAnimEnd();
472 | }
473 | });
474 | animatorSet.start();
475 | }
476 |
477 | /**
478 | * 起始动画结束 回调
479 | */
480 | protected void onStartAnimEnd() {
481 | test();
482 | }
483 |
484 | /**
485 | * 加载结束 回调
486 | */
487 | protected void onLoadingEnd() {
488 |
489 | }
490 |
491 | /**
492 | * 结束动画结束 回调
493 | */
494 | protected void onEndAnimEnd() {
495 | //TODO
496 | //2秒后 重新开始
497 | new Thread(new Runnable() {
498 | @Override
499 | public void run() {
500 | try {
501 | Thread.sleep(2000);
502 | } catch (Exception e) {
503 | }
504 | post(new Runnable() {
505 | @Override
506 | public void run() {
507 | currentProgress = 0;
508 | invalidate();
509 | startStartAnim();
510 | }
511 | });
512 | }
513 | }).start();
514 | }
515 | }
516 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/JumpWhirlGraphLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Path;
11 | import android.graphics.RectF;
12 | import android.util.AttributeSet;
13 |
14 | import com.zhaoli.loadings.interpolator.DecelerateAccelerateInterpolator;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | /**
20 | * Created by zhaoli on 2016/6/20.
21 | * 跳跃旋转图形加载
22 | */
23 | public class JumpWhirlGraphLoading extends BaseLoading {
24 |
25 | private final static int BACK_GROUND_COLOR = Color.parseColor("#2B2C30");
26 | private final static int SQUARE_COLOR = Color.parseColor("#E69D31");
27 | private final static int ROUND_COLOR = Color.parseColor("#E83131");
28 | private final static int TRIANGLE_COLOR = Color.parseColor("#318CEA");
29 |
30 | private final static int LINE_COLOR = Color.parseColor("#999DAC");
31 |
32 | private final static int ROUND_RADIUS = 90; //圆的半径
33 | private final static int SQUARE_LENGTH = 2 * ROUND_RADIUS; //正方形边长
34 | private final static int SQUARE_RADIUS = 30; //正方形圆角
35 | private final static int TRIANGLE_LENGTH = (int) (SQUARE_LENGTH / Math.cos(Math.toRadians(45))); //三角形边长
36 | private final static int TRIANGLE_IN_LENGTH = (int) (TRIANGLE_LENGTH * Math.cos(Math.toRadians(30)) -
37 | (TRIANGLE_LENGTH / 2 * Math.sin(Math.toRadians(30)))); //三角形内边长
38 |
39 | private final static int LINE_LENGTH = TRIANGLE_LENGTH;
40 | private final static int LINE_LENGTH_MIN = TRIANGLE_LENGTH / 4;
41 | private final static int LINE_HEIGHT = 6; //px
42 | private final static float LINE_M_T_SCALE = ((float) 170) / 225; //margin_top/height
43 |
44 | private final static int JUMP_HEIGHT = 2 * SQUARE_LENGTH; //2倍的正方形边长
45 |
46 | private final static float sin_30 = (float) Math.sin(Math.toRadians(30));
47 | private final static float cos_30 = (float) Math.cos(Math.toRadians(30));
48 |
49 | private final static int DURATION = 1000;
50 |
51 | private int currentWhirlAngle = 0; //当前旋转角度
52 | private int currentJumpHeight = 0; //当前跳转高度
53 | private int currentLineLength = LINE_LENGTH; //当前线长度
54 |
55 | private int graphIndex = 0; //图形index = 0 圆 1 正方形 2 三角形
56 |
57 | private Path path = new Path();
58 | private List animatorList;
59 |
60 | private RectF rectF = new RectF();
61 |
62 | public JumpWhirlGraphLoading(Context context) {
63 | super(context);
64 | initAnim();
65 | }
66 |
67 | public JumpWhirlGraphLoading(Context context, AttributeSet attrs) {
68 | super(context, attrs);
69 | initAnim();
70 | }
71 |
72 | public JumpWhirlGraphLoading(Context context, AttributeSet attrs, int defStyleAttr) {
73 | super(context, attrs, defStyleAttr);
74 | initAnim();
75 | }
76 |
77 | @Override
78 | protected void onDraw(Canvas canvas) {
79 | super.onDraw(canvas);
80 |
81 | float startY = getHeight() * LINE_M_T_SCALE;
82 | canvas.translate(getWidth() / 2, startY);
83 | //画水平线
84 | loadingPaint.setStrokeWidth(LINE_HEIGHT);
85 | loadingPaint.setColor(LINE_COLOR);
86 | canvas.drawLine(-currentLineLength / 2, 0, currentLineLength / 2, 0, loadingPaint);
87 |
88 | //画跳转图形(圆/正方形/三角形)
89 | if (graphIndex == 0) {
90 | canvas.translate(0, -currentJumpHeight - ROUND_RADIUS);
91 | } else if (graphIndex == 1) {
92 | canvas.translate(0, -currentJumpHeight - SQUARE_LENGTH / 2);
93 | canvas.rotate(currentWhirlAngle); //旋转画布
94 | } else {
95 | canvas.translate(0, -currentJumpHeight - (TRIANGLE_LENGTH * cos_30 - TRIANGLE_IN_LENGTH));
96 | canvas.rotate(-currentWhirlAngle); //旋转画布
97 | }
98 | switch (graphIndex) {
99 | case 0:
100 | loadingPaint.setColor(ROUND_COLOR);
101 | canvas.drawCircle(0, 0, ROUND_RADIUS, loadingPaint);
102 | return;
103 | case 1:
104 | loadingPaint.setColor(SQUARE_COLOR);
105 | rectF.left = -SQUARE_LENGTH / 2;
106 | rectF.top = -SQUARE_LENGTH / 2;
107 | rectF.right = SQUARE_LENGTH / 2;
108 | rectF.bottom = SQUARE_LENGTH / 2;
109 | canvas.drawRoundRect(rectF, SQUARE_RADIUS, SQUARE_RADIUS, loadingPaint);
110 | break;
111 | case 2:
112 | loadingPaint.setColor(TRIANGLE_COLOR);
113 | path.reset();
114 | path.moveTo((int) (-TRIANGLE_LENGTH * sin_30),
115 | (int) (TRIANGLE_LENGTH * cos_30 - TRIANGLE_IN_LENGTH));
116 | path.lineTo(0, -TRIANGLE_IN_LENGTH);
117 | path.lineTo((int) (TRIANGLE_LENGTH * sin_30),
118 | (int) (TRIANGLE_LENGTH * cos_30 - TRIANGLE_IN_LENGTH));
119 | path.close();
120 | canvas.drawPath(path, loadingPaint);
121 | break;
122 | }
123 | }
124 |
125 | @Override
126 | protected void initLoading() {
127 | setBackgroundColor(BACK_GROUND_COLOR);
128 |
129 | animatorList = new ArrayList<>();
130 |
131 | AnimatorSet animatorSet = new AnimatorSet();
132 |
133 | animatorList.add(getRoundAnimator());
134 | animatorList.add(getSquareAnimator());
135 | animatorList.add(getTriangleAnimator());
136 |
137 | for (int i = 0; i < animatorList.size(); i ++) {
138 | animatorList.get(i).addListener(new AnimatorListenerAdapter() {
139 | @Override
140 | public void onAnimationEnd(Animator animation) {
141 | super.onAnimationEnd(animation);
142 | graphIndex ++;
143 | if (graphIndex == 3) {
144 | graphIndex = 0;
145 | }
146 | }
147 | });
148 | }
149 |
150 | animatorSet.playSequentially(animatorList);
151 | animatorSet.addListener(new AnimatorListenerAdapter() {
152 | @Override
153 | public void onAnimationEnd(Animator animation) {
154 | super.onAnimationEnd(animation);
155 | animation.start();
156 | }
157 | });
158 | animatorSet.start();
159 | }
160 |
161 | @Override
162 | protected void initLoadingPaint() {
163 | loadingPaint.setAntiAlias(true);
164 | }
165 |
166 | private AnimatorSet getRoundAnimator() {
167 | AnimatorSet animatorSet = new AnimatorSet();
168 |
169 | ValueAnimator whirlAnim = getWhirlAnim(90);
170 | ValueAnimator lineAnim = getLineAnim();
171 | ValueAnimator jumpAnim = getJumpAnim();
172 |
173 | animatorSet.playTogether(whirlAnim, lineAnim, jumpAnim);
174 | animatorSet.setDuration(DURATION);
175 | return animatorSet;
176 | }
177 |
178 | private AnimatorSet getSquareAnimator() {
179 | AnimatorSet animatorSet = new AnimatorSet();
180 |
181 | ValueAnimator whirlAnim = getWhirlAnim(90);
182 | ValueAnimator lineAnim = getLineAnim();
183 | ValueAnimator jumpAnim = getJumpAnim();
184 |
185 | animatorSet.playTogether(whirlAnim, lineAnim, jumpAnim);
186 | animatorSet.setDuration(DURATION);
187 | return animatorSet;
188 | }
189 |
190 | private AnimatorSet getTriangleAnimator() {
191 | AnimatorSet animatorSet = new AnimatorSet();
192 |
193 | ValueAnimator whirlAnim = getWhirlAnim(120);
194 | ValueAnimator lineAnim = getLineAnim();
195 | ValueAnimator jumpAnim = getJumpAnim();
196 |
197 | animatorSet.playTogether(whirlAnim, lineAnim, jumpAnim);
198 | animatorSet.setDuration(DURATION);
199 | return animatorSet;
200 | }
201 |
202 | private ValueAnimator getLineAnim() {
203 | ValueAnimator lineAnim = ValueAnimator.ofInt(LINE_LENGTH
204 | , LINE_LENGTH_MIN, LINE_LENGTH);
205 | lineAnim.setDuration(DURATION);
206 | lineAnim.setInterpolator(new DecelerateAccelerateInterpolator());
207 | lineAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
208 | @Override
209 | public void onAnimationUpdate(ValueAnimator animation) {
210 | currentLineLength = (int) animation.getAnimatedValue();
211 | invalidate();
212 | }
213 | });
214 | return lineAnim;
215 | }
216 |
217 | private ValueAnimator getJumpAnim() {
218 | ValueAnimator jumpAnim = ValueAnimator.ofInt(0, JUMP_HEIGHT, 0);
219 | jumpAnim.setDuration(DURATION);
220 | jumpAnim.setInterpolator(new DecelerateAccelerateInterpolator());
221 | jumpAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
222 | @Override
223 | public void onAnimationUpdate(ValueAnimator animation) {
224 | currentJumpHeight = (int) animation.getAnimatedValue();
225 | invalidate();
226 | }
227 | });
228 | return jumpAnim;
229 | }
230 |
231 | private ValueAnimator getWhirlAnim(int angle) {
232 | ValueAnimator whirlAnim = ValueAnimator.ofInt(0, angle, 2 * angle);
233 | whirlAnim.setDuration(DURATION);
234 | whirlAnim.setInterpolator(new DecelerateAccelerateInterpolator());
235 | whirlAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
236 | @Override
237 | public void onAnimationUpdate(ValueAnimator animation) {
238 | currentWhirlAngle = (int) animation.getAnimatedValue();
239 | invalidate();
240 | }
241 | });
242 | return whirlAnim;
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/LineWhirlLoading1.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.RectF;
11 | import android.util.AttributeSet;
12 | import android.view.animation.AccelerateInterpolator;
13 | import android.view.animation.DecelerateInterpolator;
14 | import android.view.animation.LinearInterpolator;
15 |
16 |
17 | /**
18 | * Created by zhaoli on 2016/6/22.
19 | * 线条旋转1
20 | */
21 | public class LineWhirlLoading1 extends BaseLoading {
22 |
23 | private final static int BACK_GROUND_COLOR = Color.parseColor("#836AFF");
24 | private final static int LINE_COLOR = Color.parseColor("#FEFEFF");
25 |
26 | private final static int CIRCULAR_RADIUS = 100;
27 | private final static int LINE_WIDTH = 10;
28 | private final static float P_CIRCULAR = (float) (2 * Math.PI * CIRCULAR_RADIUS); //周长
29 | private final static float MIN_OFFSET = LINE_WIDTH;
30 | private final static float MAX_OFFSET = P_CIRCULAR / 2 - 2 * MIN_OFFSET;
31 |
32 | private int currentAngle = 0;
33 | private float currentLength = MAX_OFFSET;
34 | private int currentRadius = 0;
35 |
36 | private ValueAnimator.AnimatorUpdateListener angleUpdateListener;
37 | private ValueAnimator.AnimatorUpdateListener lengthUpdateListener;
38 | private ValueAnimator.AnimatorUpdateListener scaleUpdateListener;
39 |
40 | private RectF rectF = new RectF();
41 |
42 | public LineWhirlLoading1(Context context) {
43 | super(context);
44 | initAnim();
45 | }
46 |
47 | public LineWhirlLoading1(Context context, AttributeSet attrs) {
48 | super(context, attrs);
49 | initAnim();
50 | }
51 |
52 | public LineWhirlLoading1(Context context, AttributeSet attrs, int defStyleAttr) {
53 | super(context, attrs, defStyleAttr);
54 | initAnim();
55 | }
56 |
57 | @Override
58 | protected void onDraw(Canvas canvas) {
59 | super.onDraw(canvas);
60 |
61 | canvas.translate(getWidth() / 2, getHeight() / 2);
62 |
63 | canvas.rotate(currentAngle);
64 | int lengthToAngle = (int) (currentLength / P_CIRCULAR * 360); //弧长角度
65 |
66 | rectF.set(-CIRCULAR_RADIUS + currentRadius,
67 | -CIRCULAR_RADIUS + currentRadius,
68 | CIRCULAR_RADIUS - currentRadius,
69 | CIRCULAR_RADIUS - currentRadius);
70 | loadingPaint.setColor(LINE_COLOR);
71 | canvas.drawArc(rectF, lengthToAngle / 2, lengthToAngle, true, loadingPaint);
72 | canvas.rotate(180);
73 | canvas.drawArc(rectF, lengthToAngle / 2, lengthToAngle, true, loadingPaint);
74 |
75 | loadingPaint.setColor(BACK_GROUND_COLOR);
76 | canvas.drawCircle(0, 0, CIRCULAR_RADIUS - LINE_WIDTH - currentRadius, loadingPaint);
77 | }
78 |
79 | @Override
80 | protected void initLoading() {
81 | setBackgroundColor(BACK_GROUND_COLOR);
82 |
83 | AnimatorSet allAnim = new AnimatorSet();
84 |
85 | AnimatorSet animatorSet1 = getWhirlAnim();
86 | animatorSet1.setDuration(800);
87 | AnimatorSet animatorSet2 = getWhirlAnim();
88 | animatorSet2.setDuration(800);
89 |
90 | AnimatorSet animatorSet3 = new AnimatorSet();
91 |
92 | AnimatorSet animatorSet4 = getWhirlAnim(800);
93 | //TODO 此处有坑,慎踩
94 | /**
95 | * 例如:animatorSet1.playSequentially(A1, A2, A3);
96 | * animatorSet2.playSequentially(animatorSet1, A4);
97 | * animatorSet2.setDuration(time);
98 | * 运行起来:A1和A4同时执行,之后执行A2,A3
99 | *
100 | * 因此,必须在A1,A2,A3,A4中设置时间
101 | */
102 | animatorSet3.playTogether(animatorSet4, getScaleAnim());
103 |
104 | allAnim.playSequentially(animatorSet1, animatorSet2, animatorSet3);
105 | allAnim.setInterpolator(new LinearInterpolator());
106 | allAnim.addListener(new AnimatorListenerAdapter() {
107 | @Override
108 | public void onAnimationEnd(Animator animation) {
109 | super.onAnimationEnd(animation);
110 | animation.start();
111 | }
112 | });
113 |
114 | allAnim.start();
115 | }
116 |
117 | @Override
118 | protected void initLoadingPaint() {
119 | loadingPaint.setAntiAlias(true);
120 | }
121 |
122 | private AnimatorSet getWhirlAnim() {
123 | return getWhirlAnim(0);
124 | }
125 |
126 | private AnimatorSet getWhirlAnim(int time) {
127 | AnimatorSet animatorSet = new AnimatorSet();
128 | ValueAnimator constantSpeedWhirlAnim = getConstantSpeedWhirlAnim();
129 | AnimatorSet whirlToMinAnim = getWhirlToMinAnim();
130 | AnimatorSet whirlToMaxAnim = getWhirlToMaxAnim();
131 | animatorSet.playSequentially(constantSpeedWhirlAnim, whirlToMinAnim, whirlToMaxAnim);
132 |
133 | if (time != 0) {
134 | constantSpeedWhirlAnim.setDuration(time);
135 | whirlToMinAnim.setDuration(time);
136 | whirlToMaxAnim.setDuration(time);
137 | }
138 | return animatorSet;
139 | }
140 |
141 | private ValueAnimator getConstantSpeedWhirlAnim() {
142 | ValueAnimator valueAnimator = ValueAnimator.ofInt(135, 225);
143 | valueAnimator.setInterpolator(new LinearInterpolator());
144 | valueAnimator.addUpdateListener(getAngleUpdateListener());
145 | return valueAnimator;
146 | }
147 |
148 | private AnimatorSet getWhirlToMinAnim() {
149 | AnimatorSet animatorSet = new AnimatorSet();
150 |
151 | ValueAnimator whirlAnim = ValueAnimator.ofInt(225, 540);
152 | whirlAnim.setInterpolator(new AccelerateInterpolator());
153 | whirlAnim.addUpdateListener(getAngleUpdateListener());
154 |
155 | ValueAnimator lengthAnim = ValueAnimator.ofFloat(MAX_OFFSET, MIN_OFFSET);
156 | lengthAnim.setInterpolator(new AccelerateInterpolator());
157 | lengthAnim.addUpdateListener(getLengthUpdateListener());
158 |
159 | animatorSet.playTogether(whirlAnim, lengthAnim);
160 | return animatorSet;
161 | }
162 |
163 | private AnimatorSet getWhirlToMaxAnim() {
164 | AnimatorSet animatorSet = new AnimatorSet();
165 |
166 | ValueAnimator whirlAnim = ValueAnimator.ofInt(180, 495);
167 | whirlAnim.setInterpolator(new DecelerateInterpolator());
168 | whirlAnim.addUpdateListener(getAngleUpdateListener());
169 |
170 | ValueAnimator lengthAnim = ValueAnimator.ofFloat(MIN_OFFSET, MAX_OFFSET);
171 | lengthAnim.setInterpolator(new DecelerateInterpolator());
172 | lengthAnim.addUpdateListener(getLengthUpdateListener());
173 |
174 | animatorSet.playTogether(whirlAnim, lengthAnim);
175 | return animatorSet;
176 | }
177 |
178 | private ValueAnimator getScaleAnim() {
179 | ValueAnimator valueAnimator = ValueAnimator.ofInt(CIRCULAR_RADIUS, 0, CIRCULAR_RADIUS);
180 | valueAnimator.setInterpolator(new LinearInterpolator());
181 | valueAnimator.addUpdateListener(getScaleUpdateListener());
182 | valueAnimator.setDuration(2400);
183 | return valueAnimator;
184 | }
185 |
186 | private ValueAnimator.AnimatorUpdateListener getAngleUpdateListener() {
187 | if (angleUpdateListener == null) {
188 | angleUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
189 | @Override
190 | public void onAnimationUpdate(ValueAnimator animation) {
191 | currentAngle = (int) animation.getAnimatedValue();
192 | if (currentAngle >= 360) {
193 | currentAngle -= 360;
194 | }
195 | invalidate();
196 | }
197 | };
198 | }
199 | return angleUpdateListener;
200 | }
201 |
202 | private ValueAnimator.AnimatorUpdateListener getLengthUpdateListener() {
203 | if (lengthUpdateListener == null) {
204 | lengthUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
205 | @Override
206 | public void onAnimationUpdate(ValueAnimator animation) {
207 | currentLength = (float) animation.getAnimatedValue();
208 | invalidate();
209 | }
210 | };
211 | }
212 | return lengthUpdateListener;
213 | }
214 |
215 | private ValueAnimator.AnimatorUpdateListener getScaleUpdateListener() {
216 | if (scaleUpdateListener == null) {
217 | scaleUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
218 | @Override
219 | public void onAnimationUpdate(ValueAnimator animation) {
220 | currentRadius =CIRCULAR_RADIUS - (int) animation.getAnimatedValue();
221 | invalidate();
222 | }
223 | };
224 | }
225 | return scaleUpdateListener;
226 | }
227 |
228 |
229 | }
230 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/LineWhirlLoading2.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.RectF;
11 | import android.util.AttributeSet;
12 | import android.view.animation.AccelerateInterpolator;
13 | import android.view.animation.DecelerateInterpolator;
14 |
15 | /**
16 | * Created by zhaoli on 2016/6/22.
17 | * 线条旋转2
18 | */
19 | public class LineWhirlLoading2 extends BaseLoading{
20 |
21 | private final static int BACK_GROUND_COLOR = Color.parseColor("#2C3E50");
22 | private final static int LINE_COLOR = Color.parseColor("#FAFBFC");
23 |
24 | private final static int CIRCULAR_RADIUS = 100;
25 | private final static int LINE_WIDTH = 10;
26 |
27 | private int currentAngle1 = 0;
28 | private int currentAngle2 = 0;
29 |
30 | private RectF rectF = new RectF();
31 |
32 | public LineWhirlLoading2(Context context) {
33 | super(context);
34 | initAnim();
35 | }
36 |
37 | public LineWhirlLoading2(Context context, AttributeSet attrs) {
38 | super(context, attrs);
39 | initAnim();
40 | }
41 |
42 | public LineWhirlLoading2(Context context, AttributeSet attrs, int defStyleAttr) {
43 | super(context, attrs, defStyleAttr);
44 | initAnim();
45 | }
46 |
47 | @Override
48 | protected void onDraw(Canvas canvas) {
49 | super.onDraw(canvas);
50 | canvas.translate(getWidth() / 2, getHeight() / 2);
51 | canvas.rotate(-90);
52 |
53 | rectF.set(-CIRCULAR_RADIUS, -CIRCULAR_RADIUS, CIRCULAR_RADIUS, CIRCULAR_RADIUS);
54 | loadingPaint.setColor(LINE_COLOR);
55 | canvas.drawArc(rectF, currentAngle2, currentAngle1 - currentAngle2, true, loadingPaint);
56 |
57 | loadingPaint.setColor(BACK_GROUND_COLOR);
58 | canvas.drawCircle(0, 0, CIRCULAR_RADIUS - LINE_WIDTH, loadingPaint);
59 | }
60 |
61 | @Override
62 | protected void initLoading() {
63 | setBackgroundColor(BACK_GROUND_COLOR);
64 |
65 | AnimatorSet animatorSet = new AnimatorSet();
66 |
67 | ValueAnimator whirlAnim1 = ValueAnimator.ofInt(0, 405);
68 | whirlAnim1.setDuration(1000);
69 | whirlAnim1.setInterpolator(new AccelerateInterpolator());
70 | whirlAnim1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
71 | @Override
72 | public void onAnimationUpdate(ValueAnimator animation) {
73 | currentAngle1 = (int) animation.getAnimatedValue();
74 | if (currentAngle1 >= 360) {
75 | currentAngle1 = 360;
76 | }
77 | invalidate();
78 | }
79 | });
80 |
81 | ValueAnimator whirlAnim2 = ValueAnimator.ofInt(0, 360);
82 | whirlAnim2.setDuration(1200);
83 | whirlAnim2.setStartDelay(600);
84 | whirlAnim2.setInterpolator(new DecelerateInterpolator());
85 | whirlAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
86 | @Override
87 | public void onAnimationUpdate(ValueAnimator animation) {
88 | currentAngle2 = (int) animation.getAnimatedValue();
89 | invalidate();
90 | }
91 | });
92 | whirlAnim2.addListener(new AnimatorListenerAdapter() {
93 | @Override
94 | public void onAnimationEnd(Animator animation) {
95 | super.onAnimationEnd(animation);
96 | currentAngle2 = 0;
97 | }
98 | });
99 |
100 | animatorSet.playTogether(whirlAnim1, whirlAnim2);
101 | animatorSet.addListener(new AnimatorListenerAdapter() {
102 | @Override
103 | public void onAnimationEnd(Animator animation) {
104 | super.onAnimationEnd(animation);
105 | animation.start();
106 | }
107 | });
108 | animatorSet.start();
109 | }
110 |
111 | @Override
112 | protected void initLoadingPaint() {
113 | loadingPaint.setAntiAlias(true);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/RotateSquareLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Path;
8 | import android.util.AttributeSet;
9 | import android.view.animation.LinearInterpolator;
10 |
11 | /**
12 | * Created by zhaoli on 2016/6/18.
13 | * 旋转方块加载
14 | */
15 | public class RotateSquareLoading extends BaseLoading {
16 |
17 | private final static int SQUARE_UP_COLOR = Color.parseColor("#FED74C");
18 | private final static int SQUARE_LEFT_COLOR = Color.parseColor("#DC9633");
19 | private final static int SQUARE_RIGHT_COLOR = Color.parseColor("#C77532");
20 | private final static int SQUARE_SHADOW_COLOR = Color.parseColor("#DADADA");
21 |
22 | private final static int SQUARE_SIDE_LEGTH = 40; //px
23 |
24 | private Path path = null;
25 | private int offset = 0; //[0, SQUARE_SIDE_LEGTH]
26 | private int orientation = 0; //0 左右 1 上下
27 |
28 | private final static int angle = 60; //顶部正方形夹角
29 | private final static float sin_angle = (float) Math.sin(Math.toRadians(angle / 2));
30 | private final static float cos_angle = (float) Math.cos(Math.toRadians(angle / 2));
31 |
32 | private int[] xList = new int[7];
33 | private int[] yList = new int[7];
34 |
35 | private ValueAnimator valueAnimator;
36 |
37 | public RotateSquareLoading(Context context) {
38 | super(context);
39 | initAnim();
40 | }
41 |
42 | public RotateSquareLoading(Context context, AttributeSet attrs) {
43 | super(context, attrs);
44 | initAnim();
45 | }
46 |
47 | public RotateSquareLoading(Context context, AttributeSet attrs, int defStyleAttr) {
48 | super(context, attrs, defStyleAttr);
49 | initAnim();
50 | }
51 |
52 | @Override
53 | protected void onDraw(Canvas canvas) {
54 | super.onDraw(canvas);
55 |
56 | //移动坐标,旋转
57 | canvas.translate(getWidth() / 2, getHeight() / 2);
58 |
59 | //绘制正方体(总共有4个)
60 | if (path == null) {
61 | path = new Path();
62 | }
63 |
64 | //需要改变绘制顺序
65 | if (orientation == 0) {
66 | drawSquare(0, canvas);
67 | drawSquare(1, canvas);
68 | drawSquare(2, canvas);
69 | drawSquare(3, canvas);
70 | } else {
71 | drawSquare(2, canvas);
72 | drawSquare(0, canvas);
73 | drawSquare(3, canvas);
74 | drawSquare(1, canvas);
75 | }
76 | }
77 |
78 | @Override
79 | protected void initLoading() {
80 | valueAnimator = ValueAnimator.ofInt(SQUARE_SIDE_LEGTH, 0, -SQUARE_SIDE_LEGTH);
81 | valueAnimator.setRepeatCount(-1);
82 | valueAnimator.setDuration(1000);
83 | valueAnimator.setInterpolator(new LinearInterpolator());
84 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
85 | @Override
86 | public void onAnimationUpdate(ValueAnimator animation) {
87 | int value = (int) animation.getAnimatedValue();
88 | if (value > 0) {
89 | offset = SQUARE_SIDE_LEGTH - value;
90 | orientation = 0;
91 | } else {
92 | offset = -value;
93 | orientation = 1;
94 | }
95 | invalidate();
96 | }
97 | });
98 | valueAnimator.start();
99 | }
100 |
101 | @Override
102 | protected void initLoadingPaint() {
103 | loadingPaint.setAntiAlias(true);
104 | }
105 |
106 | private void drawPath(int point1, int point2, int point3, int point4, int color, Canvas canvas, boolean isShadow) {
107 | int shadowLength = 0;
108 | if (isShadow) {
109 | shadowLength = 7 * SQUARE_SIDE_LEGTH / 2;
110 | }
111 | path.reset();
112 | path.moveTo(xList[point1], yList[point1] + shadowLength);
113 | path.lineTo(xList[point2], yList[point2] + shadowLength);
114 | path.lineTo(xList[point3], yList[point3] + shadowLength);
115 | path.lineTo(xList[point4], yList[point4] + shadowLength);
116 | path.close();
117 | loadingPaint.setColor(color);
118 | canvas.drawPath(path, loadingPaint);
119 | }
120 |
121 | private void drawSquare(int index, Canvas canvas) {
122 |
123 | //从左角开始,顺时针
124 | switch (index) {
125 | case 0:
126 | xList[0] = (int) (((orientation == 0) ?
127 | (-3 * SQUARE_SIDE_LEGTH / 2 + offset) :
128 | (-SQUARE_SIDE_LEGTH / 2)) * cos_angle);
129 | yList[0] = (int) (((orientation == 0) ?
130 | (-3 * SQUARE_SIDE_LEGTH / 2 + offset) :
131 | (-SQUARE_SIDE_LEGTH / 2)) * sin_angle);
132 | break;
133 | case 1:
134 | xList[0] = (int) (((orientation == 0) ?
135 | (-SQUARE_SIDE_LEGTH / 2 + offset) :
136 | (SQUARE_SIDE_LEGTH / 2 - offset)) * cos_angle);
137 | yList[0] = (int) (((orientation == 0) ?
138 | (-SQUARE_SIDE_LEGTH / 2 + offset) :
139 | (SQUARE_SIDE_LEGTH / 2 + offset)) * sin_angle);
140 | break;
141 | case 2:
142 | xList[0] = (int) (((orientation == 0) ?
143 | (-3 * SQUARE_SIDE_LEGTH / 2 - offset) :
144 | (-5 * SQUARE_SIDE_LEGTH / 2 + offset)) * cos_angle);
145 | yList[0] = (int) (((orientation == 0) ?
146 | (SQUARE_SIDE_LEGTH / 2 - offset) :
147 | (-SQUARE_SIDE_LEGTH / 2 - offset)) * sin_angle);
148 | break;
149 | case 3:
150 | xList[0] = (int) (((orientation == 0) ?
151 | (-SQUARE_SIDE_LEGTH / 2 - offset) :
152 | (-3 * SQUARE_SIDE_LEGTH / 2)) * cos_angle);
153 | yList[0] = (int) (((orientation == 0) ?
154 | (3 * SQUARE_SIDE_LEGTH / 2 - offset) :
155 | (SQUARE_SIDE_LEGTH / 2)) * sin_angle);
156 | break;
157 | }
158 |
159 | xList[6] = xList[0];
160 | xList[3] = xList[2] = xList[0] + (int) (2 * SQUARE_SIDE_LEGTH * cos_angle);
161 | xList[4] = xList[5] = xList[1] = xList[0] + (int) (SQUARE_SIDE_LEGTH * cos_angle);
162 |
163 | yList[2] = yList[0];
164 | yList[1] = yList[0] - SQUARE_SIDE_LEGTH / 2;
165 | yList[5] = yList[1] + SQUARE_SIDE_LEGTH;
166 | yList[6] = yList[3] = yList[0] + SQUARE_SIDE_LEGTH;
167 | yList[4] = yList[5] + SQUARE_SIDE_LEGTH;
168 |
169 | //绘制顶部
170 | drawPath(0, 1, 2, 5, SQUARE_UP_COLOR, canvas, false);
171 | //绘制左边
172 | drawPath(0, 5, 4, 6, SQUARE_LEFT_COLOR, canvas, false);
173 | //绘制右边
174 | drawPath(2, 3, 4, 5, SQUARE_RIGHT_COLOR, canvas, false);
175 | //绘制阴影
176 | drawPath(0, 1, 2, 5, SQUARE_SHADOW_COLOR, canvas, true);
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/SegmentSquareLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Path;
8 | import android.util.AttributeSet;
9 | import android.view.animation.LinearInterpolator;
10 |
11 | /**
12 | * Created by zhaoli on 2016/6/19.
13 | * 分割方体加载
14 | */
15 | public class SegmentSquareLoading extends BaseLoading {
16 |
17 | private final static int SQUARE_UP_COLOR = Color.parseColor("#1E909A");
18 | private final static int SQUARE_LEFT_COLOR = Color.parseColor("#D53B33");
19 | private final static int SQUARE_RIGHT_COLOR = Color.parseColor("#E79C0F");
20 | private final static int BACKGROUND_COLOR = Color.parseColor("#262626");
21 |
22 | private final static int SQUARE_LENGTH = 40; //px
23 |
24 | private final static int angle = 60; //顶部正方形夹角
25 | private final static float sin_angle = (float) Math.sin(Math.toRadians(angle / 2));
26 | private final static float cos_angle = (float) Math.cos(Math.toRadians(angle / 2));
27 |
28 | private Path path = null;
29 |
30 | private int orientation = 0; //方向 0 左右 1 前后 2 上下
31 | private int offset = 0; //距离 [0, SQUARE_LENGTH / 3]
32 |
33 | //中心方体的坐标(是不变的)
34 | private int[] centerXList;
35 | private int[] centerYList;
36 |
37 | private int[] xList = new int[7];
38 | private int[] yList = new int[7];
39 |
40 | private ValueAnimator valueAnimator;
41 |
42 | public SegmentSquareLoading(Context context) {
43 | super(context);
44 | initAnim();
45 | }
46 |
47 | public SegmentSquareLoading(Context context, AttributeSet attrs) {
48 | super(context, attrs);
49 | initAnim();
50 | }
51 |
52 | public SegmentSquareLoading(Context context, AttributeSet attrs, int defStyleAttr) {
53 | super(context, attrs, defStyleAttr);
54 | initAnim();
55 | }
56 |
57 | @Override
58 | protected void onDraw(Canvas canvas) {
59 | super.onDraw(canvas);
60 |
61 | if (path == null) {
62 | path = new Path();
63 | }
64 |
65 | canvas.translate(getWidth() / 2, getHeight() / 2);
66 |
67 | for (int i = 0; i < 9; i ++) {
68 | for (int j = 2; j >= 0; j --) {
69 | drawSquare(i, j, canvas);
70 | }
71 | }
72 | }
73 |
74 | /**
75 | * 获取偏移量
76 | * @param index [0,9]
77 | * @return 偏移量
78 | */
79 | private int getOffsetX(int index) {
80 | if (orientation == 0) {
81 | if (index % 3 == 1) {
82 | return 0;
83 | } else if (index % 3 == 0) {
84 | return (int) (-offset * cos_angle);
85 | } else {
86 | return (int) (offset * cos_angle);
87 | }
88 | } else if (orientation == 1) {
89 | if (index / 3 == 1) {
90 | return 0;
91 | } else if (index / 3 == 0){
92 | return (int) (offset * cos_angle);
93 | } else {
94 | return (int) (-offset * cos_angle);
95 | }
96 | } else {
97 | return 0;
98 | }
99 | }
100 |
101 | private int getOffsetY(int index, int layout) {
102 | if (orientation == 0) {
103 | if (index % 3 == 1) {
104 | return 0;
105 | } else if (index % 3 == 0) {
106 | return (int) (-offset * sin_angle);
107 | } else {
108 | return (int) (offset * sin_angle);
109 | }
110 | } else if (orientation == 1) {
111 | if (index / 3 == 1) {
112 | return 0;
113 | } else if (index / 3 == 0){
114 | return (int) (-offset * sin_angle);
115 | } else {
116 | return (int) (offset * sin_angle);
117 | }
118 | } else {
119 | if (layout % 3 == 1) {
120 | return 0;
121 | } else if (layout % 3 == 0) {
122 | return -offset;
123 | } else {
124 | return offset;
125 | }
126 | }
127 | }
128 |
129 | /**
130 | * 获取起始点X坐标
131 | * @param index 顺序
132 | * @return X坐标
133 | */
134 | private int getStartX(int index) {
135 | int index_3 = index % 3;
136 | int index3_ = index / 3;
137 | if (orientation == 0) {
138 | if (offset >= 0) {
139 | //正向
140 | return (int) ((index_3 - (index3_ + 1)) * SQUARE_LENGTH * cos_angle);
141 | } else {
142 | //反向
143 | return (int) ((index_3 - (index3_ + 1) +
144 | (index_3 == 0 ? -1 : (index_3 == 1 ? 0 : 1)) +
145 | (index3_ == 0 ? 1 : (index3_ == 1) ? 0 : -1)) * SQUARE_LENGTH * cos_angle);
146 | }
147 | } else if (orientation == 1) {
148 | if (offset >= 0) {
149 | return (int) ((index_3 - (index3_ + 1) +
150 | (index_3 == 0 ? -1 : (index_3 == 1 ? 0 : 1))) * SQUARE_LENGTH * cos_angle);
151 | } else {
152 | return (int) ((index_3 - (index3_ + 1) +
153 | (index3_ == 0 ? 1 : (index3_ == 1) ? 0 : -1)) * SQUARE_LENGTH * cos_angle);
154 | }
155 | } else {
156 | if (offset >= 0) {
157 | return (int) ((index_3 - (index3_ + 1) +
158 | (index_3 == 0 ? -1 : (index_3 == 1 ? 0 : 1)) +
159 | (index3_ == 0 ? 1 : (index3_ == 1) ? 0 : -1)) * SQUARE_LENGTH * cos_angle);
160 | } else {
161 | return (int) ((index_3 - (index3_ + 1)) * SQUARE_LENGTH * cos_angle);
162 | }
163 | }
164 | }
165 |
166 | /**
167 | * 获取起始点Y坐标
168 | * @param index 顺序
169 | * @param layout 层
170 | * @return Y坐标
171 | */
172 | private int getStartY(int index, int layout) {
173 | int index_3 = index % 3;
174 | int index3_ = index / 3;
175 | int y;
176 | if (orientation == 0) {
177 | if (offset >= 0) {
178 | y = (int) ((index3_ + index_3 - 2) * SQUARE_LENGTH * sin_angle);
179 | } else {
180 | y = (int) ((index3_ + index_3 - 2 +
181 | (index_3 == 0 ? -1 : (index_3 == 1 ? 0 : 1)) +
182 | (index3_ == 0 ? -1 : (index3_ == 1) ? 0 : 1)) * SQUARE_LENGTH * sin_angle) +
183 | (layout == 0 ? -1 : (layout == 1) ? 0 : 1) * SQUARE_LENGTH;
184 | }
185 | } else if (orientation == 1) {
186 | if (offset >= 0) {
187 | y = (int) ((index3_ + index_3 - 2 +
188 | (index_3 == 0 ? -1 : (index_3 == 1 ? 0 : 1))) * SQUARE_LENGTH * sin_angle);
189 | } else {
190 | y = (int) ((index3_ + index_3 - 2 +
191 | (index3_ == 0 ? -1 : (index3_ == 1) ? 0 : 1)) * SQUARE_LENGTH * sin_angle) +
192 | (layout == 0 ? -1 : (layout == 1) ? 0 : 1) * SQUARE_LENGTH;
193 | }
194 | } else {
195 | if (offset >= 0) {
196 | y = (int) ((index3_ + index_3 - 2 +
197 | (index_3 == 0 ? -1 : (index_3 == 1 ? 0 : 1)) +
198 | (index3_ == 0 ? -1 : (index3_ == 1) ? 0 : 1)) * SQUARE_LENGTH * sin_angle);
199 | } else {
200 | y = (int) ((index3_ + index_3 - 2) * SQUARE_LENGTH * sin_angle) +
201 | (layout == 0 ? -1 : (layout == 1) ? 0 : 1) * SQUARE_LENGTH;
202 | }
203 | }
204 | y += (layout == 0 ? -1 : (layout == 1) ? 0 : 1) * SQUARE_LENGTH;
205 | return y;
206 | }
207 |
208 | private void drawSquare(int index, int layer, Canvas canvas) {
209 | //先计算最中心的方体坐标,是一直不变的
210 | if (index == 4 && layer == 1) {
211 | drawSquare(centerXList, centerYList, canvas);
212 | return;
213 | }
214 |
215 | xList[0] = getStartX(index) + getOffsetX(index);
216 | yList[0] = getStartY(index, layer) + getOffsetY(index, layer);
217 |
218 | xList[6] = xList[0];
219 | xList[5] = xList[4] = xList[1] = xList[0] + (int) (SQUARE_LENGTH * cos_angle);
220 | xList[3] = xList[2] = xList[0] + (int) (SQUARE_LENGTH * 2 * cos_angle);
221 |
222 | yList[2] = yList[0];
223 | yList[1] = yList[0] - SQUARE_LENGTH / 2;
224 | yList[5] = yList[0] + SQUARE_LENGTH / 2;
225 | yList[4] = yList[5] + SQUARE_LENGTH;
226 | yList[6] = yList[3] = yList[0] + SQUARE_LENGTH;
227 |
228 | drawSquare(xList, yList, canvas);
229 | }
230 |
231 | private void drawSquare(int x[], int y[], Canvas canvas) {
232 | //绘制顶部
233 | drawPath(x, y, 0, 1, 2, 5, SQUARE_UP_COLOR, canvas);
234 | //绘制左边
235 | drawPath(x, y, 0, 5, 4, 6, SQUARE_LEFT_COLOR, canvas);
236 | //绘制右边
237 | drawPath(x, y, 2, 3, 4, 5, SQUARE_RIGHT_COLOR, canvas);
238 | }
239 |
240 | private void drawPath(int x[], int y[], int point1, int point2, int point3, int point4, int color, Canvas canvas) {
241 | path.reset();
242 | path.moveTo(x[point1], y[point1]);
243 | path.lineTo(x[point2], y[point2]);
244 | path.lineTo(x[point3], y[point3]);
245 | path.lineTo(x[point4], y[point4]);
246 | path.close();
247 | loadingPaint.setColor(color);
248 | canvas.drawPath(path, loadingPaint);
249 | }
250 |
251 | @Override
252 | protected void initLoading() {
253 | setBackgroundColor(BACKGROUND_COLOR);
254 |
255 | centerXList = new int[7];
256 | centerYList = new int[7];
257 |
258 | //计算中心方体的坐标
259 | centerXList[6] = centerXList[0] = (int) (-SQUARE_LENGTH * cos_angle);
260 | centerXList[5] = centerXList[4] = centerXList[1] = 0;
261 | centerXList[3] = centerXList[2] = -centerXList[0];
262 |
263 | centerYList[2] = centerYList[0] = 0;
264 | centerYList[1] = (int) (centerYList[0] - SQUARE_LENGTH * sin_angle);
265 | centerYList[5] = SQUARE_LENGTH / 2;
266 | centerYList[4] = SQUARE_LENGTH;
267 | centerYList[6] = centerYList[3] = SQUARE_LENGTH / 2;
268 |
269 |
270 | valueAnimator = ValueAnimator.ofInt(3 * SQUARE_LENGTH, 2 * SQUARE_LENGTH, SQUARE_LENGTH, 0,
271 | - SQUARE_LENGTH, -2 * SQUARE_LENGTH, -3 * SQUARE_LENGTH);
272 | valueAnimator.setDuration(3000);
273 | valueAnimator.setRepeatCount(-1);
274 | valueAnimator.setInterpolator(new LinearInterpolator());
275 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
276 | @Override
277 | public void onAnimationUpdate(ValueAnimator animation) {
278 | int value = (int) valueAnimator.getAnimatedValue();
279 | if (value >= 2 * SQUARE_LENGTH || (value < 0 && value >= -SQUARE_LENGTH)) {
280 | orientation = 0;
281 | offset = (value > 0) ? (3 * SQUARE_LENGTH - value) : value;
282 | } else if ((value >= SQUARE_LENGTH && value < 2 * SQUARE_LENGTH) ||
283 | (value < -SQUARE_LENGTH & value >= -2 * SQUARE_LENGTH)) {
284 | orientation = 1;
285 | offset = (value > 0) ? (2 * SQUARE_LENGTH - value) : (value + SQUARE_LENGTH);
286 | } else {
287 | orientation = 2;
288 | offset = (value >= 0 ) ? (SQUARE_LENGTH - value) : (value + 2 * SQUARE_LENGTH);
289 | }
290 | invalidate();
291 | }
292 | });
293 | valueAnimator.start();
294 | }
295 |
296 | @Override
297 | protected void initLoadingPaint() {
298 | loadingPaint.setAntiAlias(true);
299 | }
300 | }
301 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/SwingCollisionLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.LinearGradient;
11 | import android.graphics.RectF;
12 | import android.graphics.Shader;
13 | import android.util.AttributeSet;
14 | import android.view.animation.AccelerateInterpolator;
15 | import android.view.animation.DecelerateInterpolator;
16 |
17 | /**
18 | * Created by zhaoli on 2016/6/17.
19 | *
20 | * 摇摆碰撞加载
21 | */
22 | public class SwingCollisionLoading extends BaseLoading {
23 |
24 | private final static int BACK_GROUND_COLOR = Color.parseColor("#ECE8DE");
25 | private final static int BALL_START_COLOR = Color.parseColor("#355773");
26 | private final static int BALL_END_COLOR = Color.parseColor("#D73B27");
27 |
28 | private final static int BALL_START_SHADOW_COLOR = Color.parseColor("#33355773");
29 | private final static int BALL_END_SHADOW_COLOR = Color.parseColor("#33D73B27");
30 |
31 | private final static int BALL_RADIUS = 16; //px
32 | private final static int BALL_MAX = 7;
33 |
34 | private LinearGradient linearGradient = null;
35 | private LinearGradient shadowLinearGradient = null;
36 | private float currentAngle = 0;
37 |
38 | private RectF shadowRectF = new RectF();
39 |
40 | public SwingCollisionLoading(Context context) {
41 | super(context);
42 | initAnim();
43 | }
44 |
45 | public SwingCollisionLoading(Context context, AttributeSet attrs) {
46 | super(context, attrs);
47 | initAnim();
48 | }
49 |
50 | public SwingCollisionLoading(Context context, AttributeSet attrs, int defStyleAttr) {
51 | super(context, attrs, defStyleAttr);
52 | initAnim();
53 | }
54 |
55 | @Override
56 | protected void onDraw(Canvas canvas) {
57 | super.onDraw(canvas);
58 |
59 | //线条长度
60 | int lineLength = BALL_RADIUS * 10;
61 |
62 | //第一步:绘制球
63 | int startX = (getWidth() - (BALL_MAX * BALL_RADIUS * 2)) / 2;
64 | int startY = (getHeight() - BALL_RADIUS * 2) / 2;
65 |
66 | if (linearGradient == null) {
67 | linearGradient = new LinearGradient(startX, startY,
68 | startX + BALL_MAX * BALL_RADIUS * 2, startY,
69 | BALL_START_COLOR, BALL_END_COLOR, Shader.TileMode.MIRROR);
70 | }
71 |
72 | //设置渐变
73 | loadingPaint.setShader(linearGradient);
74 |
75 | int index = 0;
76 | if (currentAngle > 0) {
77 | index = 1;
78 | }
79 |
80 | //绘制固定的球
81 | for (; index < ((currentAngle >= 0) ? BALL_MAX : (BALL_MAX - 1)); index ++) {
82 | canvas.drawCircle(startX + index * BALL_RADIUS * 2 + BALL_RADIUS,
83 | startY + BALL_RADIUS,
84 | BALL_RADIUS,
85 | loadingPaint);
86 | }
87 |
88 | //绘制动的球
89 | if (currentAngle > 0) {
90 | //球在左边翘起
91 | int leftX = (int) (startX + BALL_RADIUS * 3 - lineLength * Math.sin(Math.toRadians(currentAngle)));
92 | int leftY = (int) (getHeight() / 2 - lineLength + lineLength * Math.cos(Math.toRadians(currentAngle)));
93 | System.out.println();
94 | canvas.drawCircle(leftX,
95 | leftY,
96 | BALL_RADIUS,
97 | loadingPaint);
98 | } else if (currentAngle < 0) {
99 | //球在右边翘起
100 | int rightX = (int) (int) (startX + BALL_RADIUS * (BALL_MAX * 2 - 3) +
101 | lineLength * Math.sin(Math.toRadians(-currentAngle)));
102 | int rightY = (int) (getHeight() / 2 - lineLength +
103 | lineLength * Math.cos(Math.toRadians(-currentAngle)));
104 | canvas.drawCircle(rightX,
105 | rightY,
106 | BALL_RADIUS,
107 | loadingPaint);
108 | }
109 |
110 | //第二步:绘制阴影
111 | int shadowStartY = startY + BALL_RADIUS * 4;
112 |
113 | if (shadowLinearGradient == null) {
114 | shadowLinearGradient = new LinearGradient(startX, shadowStartY,
115 | startX + BALL_MAX * BALL_RADIUS * 2, shadowStartY,
116 | BALL_START_SHADOW_COLOR, BALL_END_SHADOW_COLOR, Shader.TileMode.MIRROR);
117 | }
118 |
119 | //设置渐变
120 | loadingPaint.setShader(shadowLinearGradient);
121 | for (index = (currentAngle > 0) ? 1 : 0; index < ((currentAngle > 0) ? BALL_MAX : (BALL_MAX - 1)); index ++) {
122 | shadowRectF.left = startX + index * BALL_RADIUS * 2;
123 | shadowRectF.top = shadowStartY;
124 | shadowRectF.right = startX + BALL_RADIUS * 2 + index * BALL_RADIUS * 2;
125 | shadowRectF.bottom = shadowStartY + BALL_RADIUS / 2;
126 | canvas.drawOval(shadowRectF, loadingPaint);
127 | }
128 | }
129 |
130 | @Override
131 | protected void initLoading() {
132 | //设置背景色
133 | setBackgroundColor(BACK_GROUND_COLOR);
134 |
135 | //初始化动画
136 | AnimatorSet animatorSet = new AnimatorSet();
137 | //计算初始角度(0.2为2/10 线摆长度为半径的10倍)
138 | float startAngle = (float) Math.toDegrees(Math.asin(0.2));
139 |
140 | ValueAnimator animator1 = ValueAnimator.ofFloat(startAngle, 45);
141 | animator1.setInterpolator(new DecelerateInterpolator());
142 | animator1.addUpdateListener(getAnimatorUpdateListener());
143 |
144 | ValueAnimator animator2 = ValueAnimator.ofFloat(45, startAngle);
145 | animator2.setInterpolator(new AccelerateInterpolator());
146 | animator2.addUpdateListener(getAnimatorUpdateListener());
147 |
148 | ValueAnimator animator3 = ValueAnimator.ofFloat(-startAngle, -45);
149 | animator3.setInterpolator(new DecelerateInterpolator());
150 | animator3.addUpdateListener(getAnimatorUpdateListener());
151 |
152 | ValueAnimator animator4 = ValueAnimator.ofFloat(-45, -startAngle);
153 | animator4.setInterpolator(new AccelerateInterpolator());
154 | animator4.addUpdateListener(getAnimatorUpdateListener());
155 |
156 | animatorSet.playSequentially(animator1, animator2, animator3, animator4);
157 | animatorSet.setDuration(300);
158 | animatorSet.addListener(new AnimatorListenerAdapter() {
159 | @Override
160 | public void onAnimationEnd(Animator animation) {
161 | super.onAnimationEnd(animation);
162 | animation.start();
163 | }
164 | });
165 |
166 | animatorSet.start();
167 | }
168 |
169 | @Override
170 | protected void initLoadingPaint() {
171 | //设置抗锯齿
172 | loadingPaint.setAntiAlias(true);
173 | }
174 |
175 | private ValueAnimator.AnimatorUpdateListener getAnimatorUpdateListener() {
176 | return new ValueAnimator.AnimatorUpdateListener() {
177 | @Override
178 | public void onAnimationUpdate(ValueAnimator animation) {
179 | currentAngle = (float) animation.getAnimatedValue();
180 | invalidate();
181 | }
182 | };
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/TestView.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Path;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 | import android.widget.LinearLayout;
11 |
12 | import com.zhaoli.loadings.R;
13 |
14 | /**
15 | * Created by zhaoli on 2016/6/17.
16 | */
17 | public class TestView extends View {
18 |
19 | private Path path = new Path();
20 | private Paint paint = new Paint();
21 |
22 | public TestView(Context context) {
23 | super(context);
24 | }
25 |
26 | public TestView(Context context, AttributeSet attrs) {
27 | super(context, attrs);
28 | }
29 |
30 | public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
31 | super(context, attrs, defStyleAttr);
32 | }
33 |
34 | @Override
35 | protected void onDraw(Canvas canvas) {
36 | super.onDraw(canvas);
37 |
38 | canvas.translate(0, getHeight() / 2);
39 |
40 | paint.setStyle(Paint.Style.STROKE);
41 | paint.setStrokeWidth(6);
42 |
43 | paint.setColor(Color.parseColor("#FF0000"));
44 | canvas.drawLine(0, 0, getWidth(), 0, paint);
45 |
46 | canvas.drawLine(200, -20, 200, 0, paint);
47 | canvas.drawLine(400, -20, 400, 0, paint);
48 | canvas.drawLine(600, -20, 600, 0, paint);
49 |
50 | path.reset();
51 | path.moveTo(0, 0);
52 | path.lineTo(200, 200); //直线 下一个点坐标(x, y)
53 |
54 | paint.setColor(Color.parseColor("#000000"));
55 | canvas.drawPath(path, paint);
56 |
57 | rQuadTo(200, 0, 400, -200, "#0000FF", canvas);
58 | rQuadTo(0, 200, 400, 0, "#00FF00", canvas);
59 | rQuadTo(100, -200, 200, 0, "#00FFFF", canvas);
60 | }
61 |
62 | private void startAnim() {
63 |
64 | }
65 |
66 | /**
67 | * 贝塞尔曲线
68 | * @param dx1 贝塞尔曲线控制点坐标(相差)
69 | * @param dy1 贝塞尔曲线控制点坐标(相差)
70 | * @param dx2 贝塞尔曲线终点坐标(相差)
71 | * @param dy2 贝塞尔曲线终点坐标(相差)
72 | * @param color 颜色
73 | * @param canvas 画布
74 | */
75 | private void rQuadTo(int dx1, int dy1, int dx2, int dy2, String color, Canvas canvas) {
76 | path.reset();
77 | path.moveTo(0, 0); //起点坐标
78 | path.rQuadTo(dx1, dy1, dx2, dy2);
79 | paint.setColor(Color.parseColor(color));
80 | canvas.drawPath(path, paint);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/java/com/zhaoli/loadings/loadingViews/TranslationBallLoading.java:
--------------------------------------------------------------------------------
1 | package com.zhaoli.loadings.loadingViews;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Paint;
11 | import android.util.AttributeSet;
12 | import android.view.animation.AccelerateInterpolator;
13 | import android.view.animation.DecelerateInterpolator;
14 | import android.view.animation.Interpolator;
15 | import android.view.animation.LinearInterpolator;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | /**
21 | * Created by zhaoli on 2016/6/20.
22 | *
23 | * 平移球体加载
24 | */
25 | public class TranslationBallLoading extends BaseLoading {
26 |
27 | private final static int[] BALL_COLOR = new int[] {
28 | Color.parseColor("#ED7070"),
29 | Color.parseColor("#E9995A"),
30 | Color.parseColor("#6DE9A5"),
31 | Color.parseColor("#4EB3E8"),
32 | Color.parseColor("#C25CEC")
33 | };
34 |
35 | private final static int TEXT_COLOR = Color.parseColor("#D5D5D5");
36 |
37 | private final static int SPACE_PROPORTION = 12; //Width / 13 //起始的间距
38 |
39 | private final static int BALL_MAX = 5;
40 | private final static int BALL_RADIUS = 10;
41 |
42 | private final static int SPACE_MIDDLE = 2 * BALL_RADIUS + 8; //相聚时的间距
43 |
44 | private List animatorList;
45 |
46 | private int[] xList = new int[BALL_MAX];
47 |
48 | boolean startAnimation = false;
49 |
50 | public TranslationBallLoading(Context context) {
51 | super(context);
52 | initAnim();
53 | }
54 |
55 | public TranslationBallLoading(Context context, AttributeSet attrs) {
56 | super(context, attrs);
57 | initAnim();
58 | }
59 |
60 | public TranslationBallLoading(Context context, AttributeSet attrs, int defStyleAttr) {
61 | super(context, attrs, defStyleAttr);
62 | initAnim();
63 | }
64 |
65 | @Override
66 | protected void onDraw(Canvas canvas) {
67 | super.onDraw(canvas);
68 |
69 | if (! startAnimation) {
70 | startAnimation();
71 | startAnimation = true;
72 | }
73 |
74 | int y = getHeight() / 2;
75 |
76 | for (int i = 0; i < BALL_MAX; i ++) {
77 | drawBall(i, y, canvas);
78 | }
79 |
80 | //绘制文字
81 | loadingPaint.setColor(TEXT_COLOR);
82 | loadingPaint.setTextSize(48);
83 | loadingPaint.setTextAlign(Paint.Align.CENTER);
84 | canvas.drawText("Loading...", getWidth() / 2, (float) (y * 1.5), loadingPaint);
85 | }
86 |
87 | private void drawBall(int index, int y, Canvas canvas) {
88 | loadingPaint.setColor(BALL_COLOR[index]);
89 | canvas.drawCircle(xList[index], y, BALL_RADIUS, loadingPaint);
90 | }
91 |
92 | @Override
93 | protected void initLoading() {
94 | if (animatorList == null) {
95 | animatorList = new ArrayList<>();
96 | }
97 | }
98 |
99 | private void startAnimation() {
100 | int width = getWidth();
101 |
102 | int space = width / SPACE_PROPORTION;
103 |
104 | AnimatorSet animatorSet = new AnimatorSet();
105 | for (int i = 0; i < BALL_MAX; i ++) {
106 | AnimatorSet animatorSet1 = new AnimatorSet();
107 |
108 | int middleSpace = width / 2 - i * SPACE_MIDDLE +
109 | (BALL_MAX * BALL_RADIUS * 2 + (BALL_MAX - 1) * (SPACE_MIDDLE - 2 * BALL_RADIUS)) / 2;
110 |
111 | ValueAnimator valueAnimator1 = ValueAnimator.ofInt(- i * space, middleSpace);
112 | valueAnimator1.addUpdateListener(getAnimatorUpdateListener(i));
113 | valueAnimator1.setInterpolator(getInterpolator(i, false));
114 | valueAnimator1.setDuration(3000);
115 |
116 | ValueAnimator valueAnimator2 = ValueAnimator.ofInt(middleSpace, width - i * space);
117 | valueAnimator2.addUpdateListener(getAnimatorUpdateListener(i));
118 | valueAnimator2.setInterpolator(getInterpolator(i, true));
119 | valueAnimator2.setDuration(1500);
120 |
121 | animatorSet1.addListener(new AnimatorListenerAdapter() {
122 | @Override
123 | public void onAnimationEnd(Animator animation) {
124 | super.onAnimationEnd(animation);
125 | animation.start();
126 | }
127 | });
128 | animatorSet1.playSequentially(valueAnimator1, valueAnimator2);
129 | animatorSet1.setInterpolator(new LinearInterpolator());
130 | animatorSet1.start();
131 | animatorList.add(animatorSet1);
132 | }
133 | animatorSet.playTogether(animatorList);
134 | animatorSet.start();
135 | }
136 |
137 | private ValueAnimator.AnimatorUpdateListener getAnimatorUpdateListener(final int index) {
138 | return new ValueAnimator.AnimatorUpdateListener() {
139 | @Override
140 | public void onAnimationUpdate(ValueAnimator animation) {
141 | xList[index] = (int) animation.getAnimatedValue();
142 | invalidate();
143 | }
144 | };
145 | }
146 |
147 | private Interpolator getInterpolator(int index, boolean isAcc) {
148 | if (isAcc) {
149 | return new AccelerateInterpolator(index + 1);
150 | }
151 | if (index < (BALL_MAX / 2 + 1)) {
152 | return new DecelerateInterpolator((BALL_MAX / 2 + 1) - index);
153 | } else if (index > (BALL_MAX / 2 + 1)) {
154 | return new AccelerateInterpolator(index - (BALL_MAX / 2 + 1));
155 | } else {
156 | return new LinearInterpolator();
157 | }
158 | }
159 |
160 | @Override
161 | protected void initLoadingPaint() {
162 | loadingPaint.setAntiAlias(true);
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/drawable/loading_item_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/layout/loading_item_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/layout/main_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/layout/test_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/LoadingApp/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/LoadingApp/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/LoadingApp/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/LoadingApp/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/LoadingApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Loadings/LoadingApp/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Loadings
3 |
4 |
--------------------------------------------------------------------------------
/Loadings/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.0.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/Loadings/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/Loadings/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':LoadingApp'
2 |
--------------------------------------------------------------------------------
/Loadings/示例/Loading01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading01.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading02.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading02.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading03.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading03.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading04.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading04.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading06.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading06.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading07.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading07.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading08.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading08.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading09.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading09.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading10.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading10.gif
--------------------------------------------------------------------------------
/Loadings/示例/Loading11.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loveShadow/PerfectLoading/2f7c87e222e7a267ccd38bdda9dd97991f9fd878/Loadings/示例/Loading11.gif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #自定义加载动画
2 | [灵感来源,动画设计来源](http://mp.weixin.qq.com/s?__biz=MjM5NTQ5MjIyMA==&mid=400603665&idx=3&sn=4e97192d34de86199ba33cb5d524cc77&scene=2&srcid=1102vbz5Y1K0vzTGKLeDTxdb&from=timeline&isappinstalled=0&uin=MTY5MDI4NDA4Mg%3D%3D&key=04dce534b3b035ef2b9162c22037a6a1f626b043ef93fd5f8630571da1bfb73b806c0c1845be61b02ecf4d7af6a8d652&devicetype=iMac+MacBookPro11%2C3+OSX+OSX+10.11.1+build(15B42)&version=11020201&lang=zh_CN&pass_ticket=Ccw4gTzWdRRgQlUTS3FRKMvcvEW0%2FQ1EVlRdgrv%2BfJRCXJxO2Irjh5hIHMni2E7p)
3 |
4 | ##加载动画介绍
5 | ###1. ConvertBallLoading
6 | 效果图
7 |
8 | 
9 |
10 | ###2. JumpWhirlGraphLoading
11 | 效果图
12 |
13 | 
14 |
15 | ###3. TranslationBallLoading
16 | 效果图
17 |
18 | 
19 |
20 | ###4. SegmentSquareLoading
21 | 效果图
22 |
23 | 
24 |
25 | ###5. SwingCollisionLoading
26 | 效果图
27 |
28 | 
29 |
30 | ###6. RotateSquareLoading
31 | 效果图
32 |
33 | 
34 |
35 | ###7. LineWhirlLoading1
36 | 效果图
37 |
38 | 
39 |
40 | ###8. LineWhirlLoading2
41 | 效果图
42 |
43 | 
44 |
45 | ###9. DownloadLoading
46 | 效果图
47 |
48 | 
49 |
50 | ###10. AnnulusWhirlLoading
51 | 效果图
52 |
53 | 
54 |
55 |
56 | ##动画暂时维护到这,之后有时间在增加好看的动画
--------------------------------------------------------------------------------