├── ._.DS_Store ├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── Demo1.gif ├── Demo2.gif ├── README.md ├── StructureShow.png ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── yellow5a5 │ │ └── demo │ │ └── boilingloadingview │ │ └── ApplicationTest.java │ ├── main │ ├── ._.DS_Store │ ├── AndroidManifest.xml │ ├── java │ │ └── yellow5a5 │ │ │ └── demo │ │ │ └── boilingloadingview │ │ │ ├── BoilingDialog.java │ │ │ ├── LoadingDemo.java │ │ │ ├── MainActivity.java │ │ │ ├── Util │ │ │ └── Bubble.java │ │ │ └── View │ │ │ ├── BoilingPanView.java │ │ │ ├── FlameView.java │ │ │ └── WaterView.java │ └── res │ │ ├── ._.DS_Store │ │ ├── anim │ │ ├── left_in_anim.xml │ │ └── right_in_anim.xml │ │ ├── drawable │ │ ├── ._.DS_Store │ │ ├── carrot.png │ │ ├── cover.png │ │ ├── layout_bg.xml │ │ ├── pan.png │ │ ├── panview_bg.xml │ │ ├── pea.xml │ │ ├── potato.png │ │ ├── water.png │ │ └── water_bg.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── boiling_pan.xml │ │ ├── dialog_layout.xml │ │ └── loading_layout.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 │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── yellow5a5 │ └── demo │ └── boilingloadingview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/._.DS_Store -------------------------------------------------------------------------------- /.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 | BoilingLoadingView -------------------------------------------------------------------------------- /.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/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /Demo1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/Demo1.gif -------------------------------------------------------------------------------- /Demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/Demo2.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## BoilingLoadingView 2 | 3 | - 作者:Yellow5A5 4 | 5 | ###简介 6 | --- 7 |   这是一个锅煮萝卜的Loading动画,效果仿照自之前IOS上看到的一个效果,觉得挺有意思,就搬过来了-。- 8 | 9 |   在此做成了Dialog的样式,方便作为LoadingView去使用。 10 | 11 | ###效果图 12 | --- 13 | ![image](https://github.com/Yellow5A5/BoilingLoadingView/blob/master/Demo1.gif) 14 | 15 | ![image](https://github.com/Yellow5A5/BoilingLoadingView/blob/master/Demo2.gif) 16 | 17 | ###结构 18 | --- 19 | ![image](https://github.com/Yellow5A5/BoilingLoadingView/blob/master/StructureShow.png) 20 | 21 | ###引入调用 22 | --- 23 |   动画分别两个阶段: 24 | 25 | - 1、各种蔬菜进入,锅盖盖上 26 | - 2、开始加水煮菜喷锅 27 | 28 | BoilingDialog(Loading)参考: 29 | ``` 30 | BoilingDialog.Builder builder = new BoilingDialog.Builder(MainActivity.this); 31 | final BoilingDialog dialog = builder.build(); 32 | dialog.show(); 33 | ``` 34 | 35 | 36 |   不使用Dialog的情况,直接调用BoilingPanView的beginFirstInAnim方法(第一个动画): 37 | ``` 38 | buttonInit.setOnClickListener(new View.OnClickListener(){ 39 | @Override 40 | public void onClick(View v) { 41 | mBoilingPanView.beginFirstInAnim(); 42 | } 43 | }); 44 | ``` 45 | 46 |   在第一个动画结束时自动执行第二个动画(beginBoilingAnim) 47 | ``` 48 | @Override 49 | public void onAnimationEnd(Animation animation) { 50 | if (mBoilingAnimListener != null) { 51 | //这里是为了给外部留有操作的空间 52 | mBoilingAnimListener.onFirstAnimEnd(); 53 | } else { 54 | beginBoilingAnim(); 55 | } 56 | } 57 | ``` 58 |   可以看到我在第一个动画结束加入了回调,通过实现回调可以由使用者自己去决定第二个动画播放的时机。 59 | ``` 60 | public interface BoilingAnimListener { 61 | //初始动画结束监听 62 | void onFirstAnimEnd(); 63 | } 64 | 65 | public void setBoilingAnimListener(BoilingAnimListener l) { 66 | this.mBoilingAnimListener = l; 67 | } 68 | ``` -------------------------------------------------------------------------------- /StructureShow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/StructureShow.png -------------------------------------------------------------------------------- /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 "yellow5a5.demo.boilingloadingview" 9 | minSdkVersion 14 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 /Users/Weiwu/Library/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/yellow5a5/demo/boilingloadingview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview; 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/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/._.DS_Store -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/yellow5a5/demo/boilingloadingview/BoilingDialog.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview; 2 | 3 | /** 4 | * Created by Weiwu on 16/2/1. 5 | */ 6 | 7 | import android.app.Dialog; 8 | import android.content.Context; 9 | import android.text.TextUtils; 10 | import android.view.Gravity; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.view.Window; 15 | import android.view.WindowManager; 16 | import android.widget.Button; 17 | import android.widget.TextView; 18 | 19 | import yellow5a5.demo.boilingloadingview.View.BoilingPanView; 20 | 21 | /** 22 | * Created by Weiwu on 15/12/26. 23 | */ 24 | public class BoilingDialog extends Dialog { 25 | 26 | protected View mContentView; 27 | 28 | public BoilingDialog(Context context) { 29 | super(context); 30 | } 31 | 32 | public BoilingDialog(Context context, int theme) { 33 | super(context, theme); 34 | } 35 | 36 | 37 | @Override 38 | public void show() { 39 | this.setContentView(mContentView); 40 | super.show(); 41 | } 42 | 43 | public static class Builder { 44 | protected Context context; 45 | protected BoilingDialog dialog; 46 | protected View dialogLayout; 47 | protected String titleText; 48 | protected String positiveText; 49 | protected int gifResId; 50 | 51 | public Builder(Context context){ 52 | this.context = context; 53 | } 54 | 55 | 56 | 57 | public void setupViews(){ 58 | dialog.getWindow().setGravity(Gravity.CENTER); 59 | dialogLayout = LayoutInflater.from(context).inflate(R.layout.dialog_layout, (ViewGroup)null); 60 | 61 | BoilingPanView boilingView = (BoilingPanView)dialogLayout.findViewById(R.id.boiling_show); 62 | boilingView.beginFirstInAnim(); 63 | dialog.mContentView = dialogLayout; 64 | } 65 | 66 | public BoilingDialog build() { 67 | dialog = new BoilingDialog(this.context,R.style.Translucent_NoTitle); 68 | setupViews(); 69 | return dialog; 70 | } 71 | 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/yellow5a5/demo/boilingloadingview/LoadingDemo.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Button; 7 | 8 | import yellow5a5.demo.boilingloadingview.View.BoilingPanView; 9 | 10 | public class LoadingDemo extends Activity { 11 | 12 | private Button buttonInit; 13 | private Button button1; 14 | private Button resetBtn; 15 | private BoilingPanView mBoilingPanView; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.loading_layout); 21 | initView(); 22 | initListener(); 23 | 24 | } 25 | 26 | private void initView() { 27 | buttonInit = (Button) findViewById(R.id.btn_init); 28 | resetBtn = (Button) findViewById(R.id.btn_reset); 29 | 30 | mBoilingPanView = (BoilingPanView) findViewById(R.id.loading_view); 31 | } 32 | 33 | private void initListener() { 34 | buttonInit.setOnClickListener(new View.OnClickListener(){ 35 | @Override 36 | public void onClick(View v) { 37 | mBoilingPanView.beginFirstInAnim(); 38 | } 39 | }); 40 | 41 | resetBtn.setOnClickListener(new View.OnClickListener() { 42 | @Override 43 | public void onClick(View v) { 44 | mBoilingPanView.resetAnim(); 45 | } 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/yellow5a5/demo/boilingloadingview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | public class MainActivity extends Activity { 10 | 11 | private Button button1; 12 | private Button button2; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | button1 = (Button) findViewById(R.id.first_demo); 19 | button2 = (Button) findViewById(R.id.second_demo); 20 | 21 | button1.setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(View v) { 24 | Intent intent = new Intent(MainActivity.this, LoadingDemo.class); 25 | startActivity(intent); 26 | } 27 | }); 28 | button2.setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View v) { 31 | BoilingDialog.Builder builder = new BoilingDialog.Builder(MainActivity.this); 32 | final BoilingDialog dialog = builder.build(); 33 | dialog.show(); 34 | } 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/yellow5a5/demo/boilingloadingview/Util/Bubble.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview.Util; 2 | 3 | /** 4 | * Created by Weiwu on 16/1/3. 5 | */ 6 | public class Bubble { 7 | 8 | private static final float MAX_WIDTH = 25; 9 | 10 | private float centerX; 11 | private float centerY; 12 | 13 | 14 | private float radius; 15 | 16 | private float riseSpeed; 17 | private float largenSpeed; 18 | 19 | public Bubble(float centerX, float centerY, float radius) { 20 | this.centerX = centerX; 21 | this.centerY = centerY; 22 | } 23 | 24 | //TODO 这部分晚点抽离到动画控制中。 25 | public void beenLargen() { 26 | if (radius < MAX_WIDTH) { 27 | radius += largenSpeed; 28 | } 29 | } 30 | 31 | public void beenRise() { 32 | centerY -= riseSpeed; 33 | } 34 | 35 | public void setRiseSpeed(float riseSpeed) { 36 | this.riseSpeed = riseSpeed; 37 | } 38 | 39 | public void setLargenSpeed(float largenSpeed) { 40 | this.largenSpeed = largenSpeed; 41 | } 42 | 43 | 44 | public float getCenterX() { 45 | return centerX; 46 | } 47 | 48 | public void setCenterX(float centerX) { 49 | this.centerX = centerX; 50 | } 51 | 52 | public float getCenterY() { 53 | return centerY; 54 | } 55 | 56 | public void setCenterY(float centerY) { 57 | this.centerY = centerY; 58 | } 59 | 60 | public float getRadius() { 61 | return radius; 62 | } 63 | 64 | public void setRadius(float radius) { 65 | this.radius = radius; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/yellow5a5/demo/boilingloadingview/View/BoilingPanView.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview.View; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ValueAnimator; 6 | import android.content.Context; 7 | import android.graphics.drawable.ClipDrawable; 8 | import android.os.Handler; 9 | import android.os.Message; 10 | import android.util.AttributeSet; 11 | import android.util.TypedValue; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.animation.Animation; 15 | import android.view.animation.AnimationUtils; 16 | import android.widget.ImageView; 17 | import android.widget.RelativeLayout; 18 | 19 | import java.util.Timer; 20 | import java.util.TimerTask; 21 | 22 | import yellow5a5.demo.boilingloadingview.R; 23 | 24 | /** 25 | * Created by Weiwu on 16/1/2. 26 | */ 27 | public class BoilingPanView extends RelativeLayout { 28 | 29 | 30 | private View mView; 31 | private ClipDrawable mWaterDrawable; 32 | 33 | private WaterView mWaterView; 34 | private FlameView mFlameView; 35 | 36 | private View mPea1; 37 | private View mPea2; 38 | private ImageView mPotato; 39 | private ImageView mCarrot; 40 | private ImageView mCoverView; 41 | 42 | private Animation mLeftInAnim; 43 | private Animation mRightInAnim; 44 | 45 | private boolean isRightRotate = true; 46 | private ValueAnimator mCoverAnim; 47 | 48 | private BoilingAnimListener mBoilingAnimListener; 49 | 50 | public interface BoilingAnimListener { 51 | //初始动画结束监听 52 | void onFirstAnimEnd(); 53 | } 54 | 55 | public void setBoilingAnimListener(BoilingAnimListener l) { 56 | this.mBoilingAnimListener = l; 57 | } 58 | 59 | private Handler mHandle = new Handler(new Handler.Callback() { 60 | @Override 61 | public boolean handleMessage(Message msg) { 62 | if (msg.what == 0X0000) { 63 | mWaterDrawable.setLevel(mWaterDrawable.getLevel() + 800); 64 | } 65 | return false; 66 | } 67 | }); 68 | 69 | public BoilingPanView(Context context) { 70 | this(context, null); 71 | } 72 | 73 | public BoilingPanView(Context context, AttributeSet attrs) { 74 | this(context, attrs, 0); 75 | } 76 | 77 | public BoilingPanView(Context context, AttributeSet attrs, int defStyleAttr) { 78 | super(context, attrs, defStyleAttr); 79 | mView = LayoutInflater.from(context).inflate(R.layout.boiling_pan, this, true); 80 | initView(); 81 | initStartAnim(); 82 | initCoverAnim(); 83 | } 84 | 85 | private void initView() { 86 | mWaterView = (WaterView) mView.findViewById(R.id.img_water); 87 | mFlameView = (FlameView) mView.findViewById(R.id.flame); 88 | mCoverView = (ImageView) mView.findViewById(R.id.img_cover); 89 | mPea1 = mView.findViewById(R.id.img_pea1); 90 | mPea2 = mView.findViewById(R.id.img_pea2); 91 | mPotato = (ImageView) mView.findViewById(R.id.img_potato); 92 | mCarrot = (ImageView) mView.findViewById(R.id.img_carrot); 93 | mWaterDrawable = (ClipDrawable) mWaterView.getDrawable(); 94 | } 95 | 96 | private void initStartAnim() { 97 | mLeftInAnim = AnimationUtils.loadAnimation(getContext(), R.anim.left_in_anim); 98 | mRightInAnim = AnimationUtils.loadAnimation(getContext(), R.anim.right_in_anim); 99 | } 100 | 101 | /* 102 | 抖动的盖子 103 | */ 104 | private void initCoverAnim() { 105 | mCoverAnim = ValueAnimator.ofFloat(0f, 1f, 0f).setDuration(800); 106 | mCoverAnim.setRepeatMode(Animation.REVERSE); 107 | mCoverAnim.setRepeatCount(-1); 108 | mCoverAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 109 | @Override 110 | public void onAnimationUpdate(ValueAnimator animation) { 111 | float value = (float) animation.getAnimatedValue(); 112 | if (isRightRotate) { 113 | mCoverView.setRotation(value * 5); 114 | } else { 115 | mCoverView.setRotation(-value * 5); 116 | } 117 | mCoverView.setTranslationY(-value * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics())); 118 | } 119 | }); 120 | mCoverAnim.addListener(new AnimatorListenerAdapter() { 121 | @Override 122 | public void onAnimationRepeat(Animator animation) { 123 | super.onAnimationRepeat(animation); 124 | isRightRotate = !isRightRotate; 125 | } 126 | }); 127 | } 128 | 129 | /* 130 | 开始启动的动画 131 | */ 132 | public void beginFirstInAnim() { 133 | mPea1.setVisibility(VISIBLE); 134 | mPea2.setVisibility(VISIBLE); 135 | mPotato.setVisibility(VISIBLE); 136 | mCarrot.setVisibility(VISIBLE); 137 | mCoverView.setVisibility(VISIBLE); 138 | mPea1.startAnimation(mLeftInAnim); 139 | mPea2.startAnimation(mLeftInAnim); 140 | mPotato.startAnimation(mLeftInAnim); 141 | mCarrot.startAnimation(mRightInAnim); 142 | mCoverView.startAnimation(mRightInAnim); 143 | mRightInAnim.setAnimationListener(new Animation.AnimationListener() { 144 | @Override 145 | public void onAnimationStart(Animation animation) { 146 | 147 | } 148 | 149 | @Override 150 | public void onAnimationEnd(Animation animation) { 151 | if (mBoilingAnimListener != null) { 152 | //这里是为了给外部留有操作的空间 153 | mBoilingAnimListener.onFirstAnimEnd(); 154 | } else { 155 | beginBoilingAnim(); 156 | } 157 | } 158 | 159 | @Override 160 | public void onAnimationRepeat(Animation animation) { 161 | 162 | } 163 | }); 164 | } 165 | 166 | /* 167 | 开始加水燃火动画 168 | */ 169 | public void beginBoilingAnim() { 170 | final Timer timer = new Timer(); 171 | timer.schedule(new TimerTask() { 172 | @Override 173 | public void run() { 174 | mHandle.sendEmptyMessage(0X0000); 175 | if (mWaterDrawable.getLevel() >= 10000) { 176 | timer.cancel(); 177 | } 178 | } 179 | }, 0, 50); 180 | mFlameView.startFlaming(); 181 | mCoverAnim.start(); 182 | } 183 | 184 | /* 185 | 重置动画 186 | */ 187 | public void resetAnim() { 188 | mWaterDrawable.setLevel(0); 189 | mWaterView.resetBubbleAnim(); 190 | mFlameView.stopFlaming(); 191 | mPea1.setVisibility(INVISIBLE); 192 | mPea2.setVisibility(INVISIBLE); 193 | mPotato.setVisibility(INVISIBLE); 194 | mCarrot.setVisibility(INVISIBLE); 195 | mCoverView.setVisibility(INVISIBLE); 196 | 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /app/src/main/java/yellow5a5/demo/boilingloadingview/View/FlameView.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview.View; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ValueAnimator; 6 | import android.content.Context; 7 | import android.content.res.TypedArray; 8 | import android.graphics.Canvas; 9 | import android.graphics.Color; 10 | import android.graphics.LinearGradient; 11 | import android.graphics.Paint; 12 | import android.graphics.Path; 13 | import android.graphics.Shader; 14 | import android.util.AttributeSet; 15 | import android.view.View; 16 | 17 | import java.util.Random; 18 | 19 | import yellow5a5.demo.boilingloadingview.R; 20 | 21 | /** 22 | * Created by Weiwu on 16/1/4. 23 | */ 24 | public class FlameView extends View { 25 | 26 | private Paint mPaint; 27 | private Path mPath; 28 | 29 | private int mFlameNum; 30 | private float mSumWidth; 31 | private float mSumHeight; 32 | 33 | private float mSingleWidth; 34 | private float mFlameSingleHeight; 35 | 36 | private boolean isFirstAnim = true; 37 | private float mAnimPare = 0; 38 | private ValueAnimator mLayerAnim; 39 | 40 | private Random mRandom; 41 | private float CHANGE_FACTOR = 20; 42 | 43 | //是否已测量得到宽高值 44 | private boolean isFinishMeasure = false; 45 | 46 | public FlameView(Context context) { 47 | this(context, null); 48 | } 49 | 50 | public FlameView(Context context, AttributeSet attrs) { 51 | this(context, attrs, 0); 52 | } 53 | 54 | public FlameView(Context context, AttributeSet attrs, int defStyleAttr) { 55 | super(context, attrs, defStyleAttr); 56 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FlameView); 57 | mFlameNum = array.getInteger(R.styleable.FlameView_FlameView_flameNum, 5); 58 | initData(); 59 | initAnim(); 60 | } 61 | 62 | public void startFlaming() { 63 | mLayerAnim.start(); 64 | this.setVisibility(View.VISIBLE); 65 | } 66 | 67 | public void stopFlaming() { 68 | mAnimPare = 0; 69 | isFirstAnim = true; 70 | mLayerAnim.end(); 71 | this.setVisibility(View.INVISIBLE); 72 | } 73 | 74 | private void initData() { 75 | mPaint = new Paint(); 76 | mPaint.setAntiAlias(true); 77 | mPaint.setStyle(Paint.Style.FILL); 78 | mPath = new Path(); 79 | mRandom = new Random(); 80 | } 81 | 82 | private void initAnim() { 83 | mLayerAnim = ValueAnimator.ofFloat(0f, 1f, 0.8f).setDuration(3000); 84 | mLayerAnim.setRepeatMode(ValueAnimator.RESTART); 85 | mLayerAnim.setRepeatCount(-1); 86 | mLayerAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 87 | @Override 88 | public void onAnimationUpdate(ValueAnimator animation) { 89 | if (isFirstAnim) 90 | mAnimPare = (float) animation.getAnimatedValue(); 91 | invalidate(); 92 | } 93 | }); 94 | mLayerAnim.addListener(new AnimatorListenerAdapter() { 95 | @Override 96 | public void onAnimationRepeat(Animator animation) { 97 | super.onAnimationRepeat(animation); 98 | if (isFirstAnim) { 99 | isFirstAnim = false; 100 | } 101 | } 102 | }); 103 | } 104 | 105 | @Override 106 | protected void onDraw(Canvas canvas) { 107 | super.onDraw(canvas); 108 | if (!isFinishMeasure) { 109 | mSumWidth = getMeasuredWidth(); 110 | mSumHeight = getMeasuredHeight(); 111 | mSingleWidth = mSumWidth / mFlameNum; 112 | mFlameSingleHeight = mSumHeight / 4; 113 | isFinishMeasure = true; 114 | } 115 | updataFlame(canvas); 116 | } 117 | 118 | private void updataFlame(Canvas canvas) { 119 | mPath.reset(); 120 | mPath.moveTo(0, mSumHeight); 121 | for (int i = 1; i <= mFlameNum; i++) { 122 | mPath.quadTo(mSingleWidth * i - mSingleWidth / 2, mFlameSingleHeight * 3 * mAnimPare, mSingleWidth * i, mSumHeight); 123 | } 124 | for (int i = mFlameNum; i >= 1; i--) { 125 | mPath.quadTo(mSingleWidth * i - mSingleWidth / 2 + ((1 - mRandom.nextFloat()) * CHANGE_FACTOR), -mAnimPare * mSumHeight, mSingleWidth * (i - 1), mSumHeight); 126 | } 127 | //颜色变化 128 | mPaint.setShader(new LinearGradient(mSumWidth / 2, mSumHeight, mSumWidth / 2, 0, Color.YELLOW, Color.RED, Shader.TileMode.REPEAT)); 129 | canvas.drawPath(mPath, mPaint); 130 | //原本想绘制三层火焰颜色,发现效果不好,以下: 131 | // for (int layer = 3; layer > 0; layer--) { 132 | // for (int i = 1; i <= mFlameNum; i++) { 133 | // mPath.quadTo(mSingleWidth * i - mSingleWidth / 2, mFlameSingleHeight * (layer), mSingleWidth * i, mSumHeight); 134 | // } 135 | // for (int i = mFlameNum; i >= 1; i--) { 136 | // mPath.quadTo(mSingleWidth * i - mSingleWidth / 2, mFlameSingleHeight * (layer - 1), mSingleWidth * (i - 1), mSumHeight); 137 | // } 138 | // switch (layer) { 139 | // case 1: 140 | // mPaint.setColor(Color.RED); 141 | // break; 142 | // case 2: 143 | // mPaint.setColor(Color.YELLOW); 144 | // break; 145 | // case 3: 146 | // mPaint.setColor(Color.BLUE); 147 | // break; 148 | // } 149 | // canvas.drawPath(mPath, mPaint); 150 | // mPath.reset(); 151 | // mPath.moveTo(0, mSumHeight); 152 | // } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/src/main/java/yellow5a5/demo/boilingloadingview/View/WaterView.java: -------------------------------------------------------------------------------- 1 | package yellow5a5.demo.boilingloadingview.View; 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.drawable.Drawable; 8 | import android.util.AttributeSet; 9 | import android.util.Log; 10 | import android.widget.ImageView; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Random; 15 | 16 | import yellow5a5.demo.boilingloadingview.Util.Bubble; 17 | 18 | /** 19 | * Created by Weiwu on 16/1/2. 20 | */ 21 | public class WaterView extends ImageView { 22 | 23 | private final int MAX_BUBBLE_SIZE = 8; 24 | private final int RISE_SPEED = 15; 25 | private final int LARGEN_SPEED = 1; 26 | private final int BUBBLE_TIME_INTERVAL = 300; 27 | 28 | private Paint mPaint; 29 | private List mBubbleList; 30 | private Drawable mDrawable; 31 | 32 | private int mWidth; 33 | private int mHeight; 34 | private Random mRandom; 35 | private boolean isFinishMeasure = false; 36 | private boolean isSetAnim = false; 37 | 38 | public WaterView(Context context) { 39 | this(context, null); 40 | } 41 | 42 | public WaterView(Context context, AttributeSet attrs) { 43 | this(context, attrs, 0); 44 | } 45 | 46 | public WaterView(Context context, AttributeSet attrs, int defStyleAttr) { 47 | super(context, attrs, defStyleAttr); 48 | // TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.WaterView); 49 | // mDrawable = array.getDrawable(R.styleable.WaterView_WaterView_src); 50 | // mSpeed = array.getInteger(R.styleable.WaterView_WaterView_speed, 200); 51 | initPaint(); 52 | initData(); 53 | } 54 | 55 | private void initPaint() { 56 | mPaint = new Paint(); 57 | mPaint.setColor(Color.WHITE); 58 | mPaint.setAntiAlias(true); 59 | mPaint.setStrokeWidth(5); 60 | mPaint.setStyle(Paint.Style.STROKE); 61 | } 62 | 63 | private void initData() { 64 | mDrawable = getDrawable(); 65 | mRandom = new Random(); 66 | mBubbleList = new ArrayList(); 67 | } 68 | 69 | private void setDrawable(Drawable drawable) { 70 | mDrawable = drawable; 71 | setImageDrawable(mDrawable); 72 | } 73 | 74 | @Override 75 | protected void onDraw(Canvas canvas) { 76 | super.onDraw(canvas); 77 | if (mDrawable == null) 78 | return; 79 | if (!isFinishMeasure) { 80 | mWidth = getWidth(); 81 | mHeight = getHeight(); 82 | isFinishMeasure = true; 83 | return; 84 | } 85 | if (mDrawable.getLevel() != 0 && !isSetAnim) { 86 | beginAnimation(); 87 | isSetAnim = true; 88 | } 89 | setbubble(mBubbleList, canvas); 90 | } 91 | 92 | private void beginAnimation() { 93 | for (int i = 0; i < 8; i++) { 94 | addBubble(BUBBLE_TIME_INTERVAL * i); 95 | } 96 | } 97 | 98 | private void addBubble(int delay) { 99 | postDelayed(new Runnable() { 100 | @Override 101 | public void run() { 102 | if (mBubbleList.size() < MAX_BUBBLE_SIZE) { 103 | float centerX = mWidth * mRandom.nextFloat(); 104 | Bubble bubble = new Bubble(centerX, mHeight, 0); 105 | bubble.setRiseSpeed(RISE_SPEED); 106 | bubble.setLargenSpeed(LARGEN_SPEED); 107 | mBubbleList.add(bubble); 108 | } 109 | } 110 | }, delay); 111 | } 112 | 113 | private void setbubble(List list, Canvas canvas) { 114 | if (list.size() == 0) { 115 | return; 116 | } 117 | for (int i = 0; i < list.size(); i++) { 118 | Bubble bubble = list.get(i); 119 | if (bubble.getCenterY() < mHeight - mHeight * mDrawable.getLevel() / 10000f) { 120 | mBubbleList.remove(bubble); 121 | addBubble(0); 122 | } else { 123 | bubble.beenLargen(); 124 | bubble.beenRise(); 125 | } 126 | canvas.drawCircle(bubble.getCenterX(), bubble.getCenterY(), bubble.getRadius(), mPaint); 127 | } 128 | invalidate(); 129 | } 130 | 131 | public void resetBubbleAnim() { 132 | //清空消息队列 133 | getHandler().removeCallbacksAndMessages(null); 134 | isSetAnim = false; 135 | mBubbleList.clear(); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /app/src/main/res/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/res/._.DS_Store -------------------------------------------------------------------------------- /app/src/main/res/anim/left_in_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/anim/right_in_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/res/drawable/._.DS_Store -------------------------------------------------------------------------------- /app/src/main/res/drawable/carrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/res/drawable/carrot.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/res/drawable/cover.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/layout_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/res/drawable/pan.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/panview_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pea.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/potato.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/res/drawable/potato.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yellow5A5/BoilingLoadingView/a7542cb1e7ae118133bc7cca8bee6739c4290605/app/src/main/res/drawable/water.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/water_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |