├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wingsofts │ │ └── loadingview │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wingsofts │ │ │ └── loadingview │ │ │ ├── MainActivity.java │ │ │ ├── MaterialLoadingView.java │ │ │ └── SuccessView.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── layout.xml │ │ └── view_dialog.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-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── wingsofts │ └── loadingview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── loadingview.gif └── success.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | LoadingView -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | $USER_HOME$/.subversion 48 | 50 | 51 | 52 | 53 | 54 | 1.8 55 | 56 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LoadingView 2 | 这里是 loadingView的集合,会不定期增加一些效果。 3 | 4 | 另外每一种效果(也许)会对应一篇博客讲解如何实现。 5 | 6 | ## 效果1:loading 7 | 8 | 博客讲解地址:http://androidwing.net/index.php/73 9 | 10 | ![image](https://github.com/githubwing/LoadingView/raw/master/img/loadingview.gif) 11 | 12 | ## 效果2:success 13 | 14 | 博客讲解地址:http://blog.csdn.net/wingichoy/article/details/50482271 15 | 16 | ![image](https://github.com/githubwing/LoadingView/raw/master/img/success.gif) 17 | 18 | # License 19 | 20 | Copyright 2016 androidwing1992 21 | 22 | Licensed under the Apache License, Version 2.0 (the "License"); 23 | you may not use this file except in compliance with the License. 24 | You may obtain a copy of the License at 25 | 26 | http://www.apache.org/licenses/LICENSE-2.0 27 | 28 | Unless required by applicable law or agreed to in writing, software 29 | distributed under the License is distributed on an "AS IS" BASIS, 30 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | See the License for the specific language governing permissions and 32 | limitations under the License. 33 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.wingsofts.loadingview" 9 | minSdkVersion 15 10 | targetSdkVersion 23 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(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.1.1' 26 | } 27 | -------------------------------------------------------------------------------- /app/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:\Android Tools\Android-SDK-Tools/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/wingsofts/loadingview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.wingsofts.loadingview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/wingsofts/loadingview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wingsofts.loadingview; 2 | 3 | import android.app.Activity; 4 | import android.support.v7.app.AlertDialog; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | public class MainActivity extends Activity { 8 | private SuccessView mSuccessView; 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | setContentView(R.layout.activity_main); 13 | 14 | 15 | } 16 | 17 | public void successDialog(View v){ 18 | new AlertDialog.Builder(this).setView(R.layout.layout).setNegativeButton("OK",null).create().show(); 19 | } 20 | 21 | public void loadingDialog(View v) { 22 | View view = View.inflate(this, R.layout.view_dialog, null); 23 | AlertDialog dialog = new AlertDialog.Builder(this).setView(view).create(); 24 | dialog.getWindow().setLayout(dip2px(400), dip2px(200)); 25 | dialog.show(); 26 | } 27 | 28 | 29 | 30 | public int dip2px(float dipValue) { 31 | final float scale = getResources().getDisplayMetrics().density; 32 | return (int) (dipValue * scale + 0.5f); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/wingsofts/loadingview/MaterialLoadingView.java: -------------------------------------------------------------------------------- 1 | package com.wingsofts.loadingview; 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.util.Log; 10 | import android.view.View; 11 | 12 | /** 13 | * Created by wing on 16/9/9. 14 | */ 15 | public class MaterialLoadingView extends View { 16 | 17 | private int mWidth; 18 | private int mHeight; 19 | private Paint mPaint; 20 | private Path mPath; 21 | private int mColor = Color.WHITE; 22 | private int mMaxRadius = 30; 23 | //旋转的角度 24 | private float mDegrees; 25 | 26 | //两个小球的偏移量 27 | private float mOffset; 28 | 29 | private float mMaxOffset = 100; 30 | 31 | public MaterialLoadingView(Context context) { 32 | this(context, null); 33 | } 34 | 35 | public MaterialLoadingView(Context context, AttributeSet attrs) { 36 | this(context, attrs, 0); 37 | } 38 | 39 | public MaterialLoadingView(Context context, AttributeSet attrs, int defStyleAttr) { 40 | super(context, attrs, defStyleAttr); 41 | mPaint = new Paint(); 42 | mPaint.setColor(mColor); 43 | mPaint.setAntiAlias(true); 44 | mPath = new Path(); 45 | } 46 | 47 | @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 48 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 49 | mWidth = MeasureSpec.getSize(widthMeasureSpec); 50 | mHeight = MeasureSpec.getSize(heightMeasureSpec); 51 | } 52 | 53 | @Override protected void onDraw(Canvas canvas) { 54 | super.onDraw(canvas); 55 | 56 | canvas.rotate(mDegrees += 3, mWidth / 2, mHeight / 2); 57 | 58 | float present = mDegrees / 360; 59 | if (present < 0.5) { 60 | mOffset = mMaxOffset * present; 61 | } else { 62 | mOffset = mMaxOffset * (1 - present); 63 | } 64 | drawCircle(canvas, present); 65 | if (present <= 0.37 || present >= 0.63) drawPath(canvas, present); 66 | if (mDegrees == 360) { 67 | mDegrees = 0; 68 | } 69 | invalidate(); 70 | } 71 | 72 | private void drawPath(Canvas canvas, float present) { 73 | mPath.reset(); 74 | mPath.moveTo(mWidth / 2 - mMaxRadius, mHeight / 2 - mOffset); 75 | mPath.lineTo(mWidth / 2 + mMaxRadius, mHeight / 2 - mOffset); 76 | 77 | float supportOffset = -30; 78 | 79 | if (present < 0.25) { //两个球相交 80 | supportOffset = 30; 81 | } else if (present >= 0.25 && present < 0.375f) { 82 | Log.e("present", present + ""); 83 | supportOffset = -(480 * present - 150f); 84 | } else if (present > 0.625) { //开始缩小 85 | 86 | supportOffset = (480 * present - 330f); 87 | if (present > 0.75) { //两个球开始相交 88 | supportOffset = 30; 89 | } 90 | //supportOffset = 30; 91 | } 92 | 93 | Log.e("wing", supportOffset + ""); 94 | 95 | mPath.quadTo(mWidth / 2 + supportOffset, mHeight / 2, mWidth / 2 + mMaxRadius, 96 | mHeight / 2 + mOffset); 97 | mPath.lineTo(mWidth / 2 - mMaxRadius, mHeight / 2 + mOffset); 98 | mPath.quadTo(mWidth / 2 - supportOffset, mHeight / 2, mWidth / 2 - mMaxRadius, 99 | mHeight / 2 - mOffset); 100 | mPath.close(); 101 | mPaint.setStyle(Paint.Style.FILL); 102 | canvas.drawPath(mPath, mPaint); 103 | } 104 | 105 | private void drawCircle(Canvas canvas, float present) { 106 | 107 | canvas.drawCircle(mWidth / 2, mHeight / 2 - mOffset, mMaxRadius, mPaint); 108 | canvas.drawCircle(mWidth / 2, mHeight / 2 + mOffset, mMaxRadius, mPaint); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/wingsofts/loadingview/SuccessView.java: -------------------------------------------------------------------------------- 1 | package com.wingsofts.loadingview; 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.graphics.RectF; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | 12 | /** 13 | * 注意:!!~!!!!此类有错误,错误示范!!!!!!! 不要在onDraw里new对象!!!! 14 | * Created by Wing on 2016/1/8. 15 | */ 16 | public class SuccessView extends View { 17 | private int mWidth; 18 | private int mHeight; 19 | private Context mContext; 20 | 21 | //横线变对勾的百分比 22 | private int mLinePercent; 23 | 24 | public void start() { 25 | if (isDrawing == false) { 26 | canStartDraw = true; 27 | isRiseDone = false; 28 | mRisePercent = 0; 29 | mLineShrinkPercent = 0; 30 | mCirclePercent = 0; 31 | mPathPercent = 0; 32 | mLinePercent = 0; 33 | invalidate(); 34 | } 35 | } 36 | 37 | //标记是否可以开始动画 38 | private boolean canStartDraw = true; 39 | 40 | private int mRisePercent = 0; 41 | 42 | //竖线缩短的百分比 43 | private int mLineShrinkPercent = 0; 44 | 45 | //圆形进度百分比 46 | private int mCirclePercent = 0; 47 | 48 | //标记上升是否完成 49 | private boolean isRiseDone = false; 50 | 51 | //对勾变形的百分比 52 | private int mPathPercent = 0; 53 | 54 | //判断是不是正在draw 55 | private boolean isDrawing = false; 56 | 57 | private boolean isPathToLine = false; 58 | 59 | public SuccessView(Context context) { 60 | this(context, null); 61 | } 62 | 63 | public SuccessView(Context context, AttributeSet attrs) { 64 | this(context, attrs, 0); 65 | } 66 | 67 | public SuccessView(Context context, AttributeSet attrs, int defStyleAttr) { 68 | super(context, attrs, defStyleAttr); 69 | mContext = context; 70 | } 71 | 72 | @Override 73 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 74 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 75 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 76 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 77 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 78 | if (widthMode == MeasureSpec.EXACTLY) { 79 | mWidth = widthSize; 80 | } else { 81 | mWidth = 200; 82 | } 83 | 84 | 85 | if (heightMode == MeasureSpec.EXACTLY) { 86 | mHeight = heightSize; 87 | } else { 88 | mHeight = 200; 89 | } 90 | setMeasuredDimension(mWidth, mHeight); 91 | } 92 | 93 | @Override 94 | protected void onDraw(Canvas canvas) { 95 | Paint p = new Paint(); 96 | 97 | Path path = new Path(); 98 | p.setColor(Color.parseColor("#2EA4F2")); 99 | p.setStyle(Paint.Style.STROKE); 100 | p.setStrokeWidth(8); 101 | p.setAntiAlias(true); 102 | 103 | //百分比弧的矩形 104 | RectF rectF = new RectF(5, 5, mWidth - 5, mHeight - 5); 105 | 106 | //绘制圆 107 | canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - 5, p); 108 | 109 | 110 | if (canStartDraw) { 111 | isDrawing = true; 112 | //开始变形 113 | p.setColor(Color.WHITE); 114 | 115 | //如果小于95 就继续缩短。 95是微调值 和point大小相等 116 | if (mLineShrinkPercent < 95) { 117 | //线段逐渐缩短(终点为mWidth/2,mHeight/2) 118 | float tmp = (mWidth / 2 - mHeight / 4) * mLineShrinkPercent / 100; 119 | canvas.drawLine(mWidth / 2, mHeight / 4 + tmp, mWidth / 2, mHeight * 0.75f - tmp, p); 120 | mLineShrinkPercent += 5; 121 | } else { 122 | //path变成直线 123 | isPathToLine = true; 124 | if (mPathPercent < 100) { 125 | 126 | path.moveTo(mWidth / 4, mHeight * 0.5f); 127 | path.lineTo(mWidth / 2, mHeight * 0.75f - mPathPercent / 100f * 0.25f * mHeight); 128 | path.lineTo(mWidth * 0.75f, mHeight * 0.5f); 129 | canvas.drawPath(path, p); 130 | mPathPercent += 5; 131 | 132 | //在变成直线的过程中这个点一直存在 133 | canvas.drawCircle(mWidth / 2, mHeight / 2,2.5f, p); 134 | } else { 135 | //绘制把点上弹的直线 136 | 137 | //画上升的点 138 | if (mRisePercent < 100) { 139 | 140 | //在点移动到圆弧上的时候 线是一直存在的 141 | canvas.drawLine(mWidth / 4, mHeight * 0.5f, mWidth * 0.75f, mHeight * 0.5f, p); 142 | 143 | canvas.drawCircle(mWidth / 2, mHeight / 2 - mHeight / 2 * mRisePercent / 100 + 5,2.5f, p); 144 | 145 | mRisePercent += 5; 146 | } else { 147 | //上升的点最终的位置 148 | canvas.drawPoint(mWidth / 2, 5, p); 149 | isRiseDone = true; 150 | 151 | //改变对勾形状 152 | if (mLinePercent < 100) { 153 | 154 | path.moveTo(mWidth / 4, mHeight * 0.5f); 155 | path.lineTo(mWidth / 2, mHeight * 0.5f+ mLinePercent/100f * mHeight * 0.25f); 156 | path.lineTo(mWidth * 0.75f, mHeight * 0.5f - mLinePercent / 100f * mHeight * 0.3f); 157 | canvas.drawPath(path, p); 158 | mLinePercent += 5; 159 | 160 | //动态绘制圆形百分比 161 | if (mCirclePercent < 100) { 162 | canvas.drawArc(rectF, 270, -mCirclePercent / 100.0f * 360, false, p); 163 | mCirclePercent += 5; 164 | } 165 | 166 | } else { 167 | //绘制最终的path 168 | path.moveTo(mWidth / 4, mHeight * 0.5f); 169 | path.lineTo(mWidth / 2, mHeight * 0.75f); 170 | path.lineTo(mWidth * 0.75f, mHeight * 0.3f); 171 | canvas.drawPath(path, p); 172 | // 绘制最终的圆 173 | canvas.drawArc(rectF, 270, -360, false, p); 174 | 175 | isDrawing = false; 176 | 177 | } 178 | // } 179 | } 180 | 181 | 182 | } 183 | 184 | 185 | } 186 | 187 | if (!isPathToLine) { 188 | path.moveTo(mWidth / 4, mHeight * 0.5f); 189 | path.lineTo(mWidth / 2, mHeight * 0.75f); 190 | path.lineTo(mWidth * 0.75f, mHeight * 0.5f); 191 | canvas.drawPath(path, p); 192 | } 193 | 194 | } else { 195 | //绘制静态箭头 196 | p.setColor(Color.WHITE); 197 | canvas.drawLine(mWidth / 2, mHeight / 4, mWidth / 2, mHeight * 0.75f, p); 198 | // Path path = new Path(); 199 | path.moveTo(mWidth / 4, mHeight * 0.5f); 200 | path.lineTo(mWidth / 2, mHeight * 0.75f); 201 | path.lineTo(mWidth * 0.75f, mHeight * 0.5f); 202 | canvas.drawPath(path, p); 203 | } 204 | 205 | 206 | postInvalidateDelayed(10); 207 | super.onDraw(canvas); 208 | } 209 | 210 | 211 | } 212 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 |