├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── think.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── ivy
│ │ └── weather
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── ivy
│ │ │ ├── bomb
│ │ │ ├── BombActivity.java
│ │ │ └── BombView.java
│ │ │ ├── jelly
│ │ │ ├── JellyView.java
│ │ │ └── MainJellyActivity.java
│ │ │ ├── main
│ │ │ ├── IvyOnTouchListener.java
│ │ │ ├── MainActivity.java
│ │ │ └── ViewItem.java
│ │ │ ├── ruler
│ │ │ ├── RulerActivity.java
│ │ │ └── ScrollerRulerView.java
│ │ │ ├── setting
│ │ │ └── SettingActivity.java
│ │ │ └── weather
│ │ │ ├── CircleInfo.java
│ │ │ ├── CircleTypeEvaluator.java
│ │ │ ├── WeatherActivity.java
│ │ │ └── WeatherView.java
│ └── res
│ │ ├── drawable
│ │ └── a.gif
│ │ ├── layout
│ │ ├── activity_bomb.xml
│ │ ├── activity_jelly_main.xml
│ │ ├── activity_main.xml
│ │ ├── activity_ruler.xml
│ │ ├── activity_setting.xml
│ │ ├── activity_weather.xml
│ │ └── adapter_main.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
│ │ └── xml
│ │ └── shortcuts.xml
│ └── test
│ └── java
│ └── com
│ └── ivy
│ └── weather
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── 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 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.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/dictionaries/think.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Abstraction issuesJava
46 |
47 |
48 | Android Lint
49 |
50 |
51 | Assignment issuesGroovy
52 |
53 |
54 | Assignment issuesJava
55 |
56 |
57 | Bitwise operation issuesJava
58 |
59 |
60 | Class structureJava
61 |
62 |
63 | Code style issuesJava
64 |
65 |
66 | Control FlowGroovy
67 |
68 |
69 | Control flow issuesJava
70 |
71 |
72 | GPath inspectionsGroovy
73 |
74 |
75 | General
76 |
77 |
78 | GeneralJava
79 |
80 |
81 | Groovy
82 |
83 |
84 | HTML
85 |
86 |
87 | Initialization issuesJava
88 |
89 |
90 | Internationalization issues
91 |
92 |
93 | Internationalization issuesJava
94 |
95 |
96 | J2ME issuesJava
97 |
98 |
99 | JUnit issues
100 |
101 |
102 | JUnit issuesJava
103 |
104 |
105 | Java
106 |
107 |
108 | Java language level issuesJava
109 |
110 |
111 | Java language level migration aidsJava
112 |
113 |
114 | Javadoc issuesJava
115 |
116 |
117 | Logging issuesJava
118 |
119 |
120 | Memory issuesJava
121 |
122 |
123 | Naming ConventionsGroovy
124 |
125 |
126 | Naming conventionsJava
127 |
128 |
129 | Numeric issuesJava
130 |
131 |
132 | Performance issuesJava
133 |
134 |
135 | Portability issuesJava
136 |
137 |
138 | Potentially confusing code constructsGroovy
139 |
140 |
141 | Probable bugsGroovy
142 |
143 |
144 | Probable bugsJava
145 |
146 |
147 | Properties Files
148 |
149 |
150 | RELAX NG
151 |
152 |
153 | Security issuesJava
154 |
155 |
156 | TestNG
157 |
158 |
159 | Threading issuesJava
160 |
161 |
162 | Visibility issuesJava
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 1. Weather view,[详细请查看文章](http://www.jianshu.com/p/2c9dc35f3aad)
3 |
4 | 
5 |
6 | 2. ScrollRuleView 依照薄荷健康的滑动卷尺效果
7 |
8 | 
9 |
10 |
11 | 3.bombView小炸弹,[详细请查看文章](http://www.jianshu.com/p/a622fa556c1b)
12 |
13 | 
14 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 | defaultConfig {
7 | applicationId "com.ivy.weather"
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
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 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.3.1'
28 | testCompile 'junit:junit:4.12'
29 | compile 'com.android.support:recyclerview-v7:25.3.1'
30 | }
31 |
--------------------------------------------------------------------------------
/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\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/com/ivy/weather/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ivy.weather;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.ivy.weather", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/bomb/BombActivity.java:
--------------------------------------------------------------------------------
1 | package com.ivy.bomb;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | import com.ivy.weather.R;
9 |
10 | /**
11 | * Created by ivy on 2017/10/25.
12 | * Description:
13 | */
14 |
15 | public class BombActivity extends AppCompatActivity {
16 | @Override
17 | protected void onCreate(@Nullable Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_bomb);
20 | final BombView bombView= (BombView) this.findViewById(R.id.bomb_view);
21 | bombView.setOnClickListener(new View.OnClickListener() {
22 | @Override
23 | public void onClick(View v) {
24 | bombView.startAnim();
25 | }
26 | });
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/bomb/BombView.java:
--------------------------------------------------------------------------------
1 | package com.ivy.bomb;
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.Camera;
9 | import android.graphics.Canvas;
10 | import android.graphics.Color;
11 | import android.graphics.DashPathEffect;
12 | import android.graphics.Matrix;
13 | import android.graphics.Paint;
14 | import android.graphics.Path;
15 | import android.graphics.PathMeasure;
16 | import android.graphics.Point;
17 | import android.graphics.PorterDuff;
18 | import android.graphics.PorterDuffXfermode;
19 | import android.graphics.RectF;
20 | import android.os.Build;
21 | import android.support.annotation.Nullable;
22 | import android.support.annotation.RequiresApi;
23 | import android.util.AttributeSet;
24 | import android.util.TypedValue;
25 | import android.view.View;
26 | import android.view.animation.DecelerateInterpolator;
27 | import static android.animation.ValueAnimator.ofFloat;
28 |
29 | /**
30 | * Created by ivy on 2017/10/24.
31 | * Description:
32 | */
33 |
34 | public class BombView extends View {
35 | private Paint mPaint;
36 | private Path mPath, mHeadLinePath ,mHeadPath ,mBodyLightPath;
37 | private int bombColor = Color.parseColor("#88B0E8");
38 | private int bombLineColor = Color.parseColor("#181D82");
39 | private int bombShadowColor = Color.parseColor("#77609ee6");
40 | private int lightColor = Color.WHITE;
41 | private int bombLineWidth;
42 | //炸弹身体半径 高光半径
43 | private int bodyRadius, highLightRadius;
44 | //用于处理线条的分割点
45 | private DashPathEffect groundDashPathEffect,bodyDashPathEffect,highLightPathEffect,mHeadEffect;
46 | private RectF mRectF;
47 | private PathMeasure mPathMeasure=new PathMeasure();
48 | private float[] mPathPosition=new float[2];
49 | //动画控制相关
50 | private float faceLROffset , faceMaxLROffset;
51 | private float faceTBOffset =0, faceMaxTBOffset;
52 | private float bombLRRotate =15, bombMaxLRRotate =15 ,bombTBRotate=0, bombMaxTBRotate =5;
53 | private float eyeRadius,eyeMaxRadius,eyeMinRadius;
54 | private float headLinePercent=1,headLineLightRate=0;
55 | private float maxBlastCircleRadius, currentBlastCircleRadius,blastCircleRadiusPercent;
56 | //用于计算mouth第二阶段变化
57 | private float mouthMaxWidthOffset, mouthMaxHeightOffset, mouthWidthOffset=0, mouthHeightOffset =0,mouthOffsetPercent=0;
58 | //用于计算mouth第一阶段变化
59 | private float mouthFSMaxWidthOffset,mouthFSMaxHeightOffset,mouthFSWidthOffset=0,mouthFSHeightOffset=0;
60 | //炸弹的中心点
61 | private int bombCenterX,bombCenterY;
62 | //用于控制旋转
63 | private Camera mCamera=new Camera();
64 | private Matrix mMatrix=new Matrix();
65 |
66 |
67 | public BombView(Context context) {
68 | super(context);
69 | init();
70 | }
71 |
72 | public BombView(Context context, @Nullable AttributeSet attrs) {
73 | super(context, attrs);
74 | init();
75 | }
76 |
77 | public BombView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
78 | super(context, attrs, defStyleAttr);
79 | init();
80 | }
81 |
82 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
83 | public BombView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
84 | super(context, attrs, defStyleAttr, defStyleRes);
85 | init();
86 | }
87 |
88 | @Override
89 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
90 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
91 | int width=getMeasuredWidth();
92 | int height=getMeasuredHeight();
93 | int minLength= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,100,getContext().getResources().getDisplayMetrics());
94 | minLength=Math.max(Math.min(width,height),minLength);
95 | setMeasuredDimension(minLength,minLength);
96 | }
97 |
98 | private void init() {
99 | mPaint=new Paint();
100 | mPaint.setAntiAlias(true);
101 | mPaint.setDither(true);
102 | mPaint.setStrokeCap(Paint.Cap.ROUND);
103 | mPaint.setStrokeJoin(Paint.Join.ROUND);
104 | mPath=new Path();
105 | mRectF=new RectF();
106 | mHeadLinePath =new Path();
107 | mHeadPath =new Path();
108 | mBodyLightPath =new Path();
109 | }
110 |
111 | @Override
112 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
113 | super.onSizeChanged(w, h, oldw, oldh);
114 | bombLineWidth =getMeasuredWidth()/35;
115 | mPaint.setStrokeWidth(bombLineWidth);
116 | float[] groundEffectFloat=new float[]{bombLineWidth/4,bombLineWidth/2+bombLineWidth,bombLineWidth*2,bombLineWidth/3*2+bombLineWidth,getMeasuredWidth(),0};
117 | groundDashPathEffect=new DashPathEffect(groundEffectFloat,0);
118 | bodyRadius= (int) (getMeasuredHeight()/3.4f);
119 | float[] bodyEffectFloat=new float[]{getRadianLength(56,bodyRadius)
120 | ,getRadianLength(4,bodyRadius)+bombLineWidth
121 | ,getRadianLength(2.5f,bodyRadius)
122 | ,getRadianLength(4,bodyRadius)+bombLineWidth
123 | ,getRadianLength(220,bodyRadius)
124 | ,getRadianLength(12,bodyRadius)+bombLineWidth
125 | ,getRadianLength(90,bodyRadius)
126 | ,0};
127 | bodyDashPathEffect=new DashPathEffect(bodyEffectFloat,0);
128 |
129 | highLightRadius =bodyRadius/3*2;
130 | float[] highLightFloat=new float[]{0,getRadianLength(95, highLightRadius)
131 | ,getRadianLength(0.5f, highLightRadius)
132 | ,getRadianLength(5, highLightRadius)+bombLineWidth
133 | ,getRadianLength(12, highLightRadius)
134 | ,getRadianLength(5, highLightRadius)+bombLineWidth
135 | ,getRadianLength(24, highLightRadius)
136 | ,getRadianLength(270, highLightRadius)};
137 | highLightPathEffect=new DashPathEffect(highLightFloat,0);
138 |
139 | float padding= (float) (2*bombLineWidth*Math.PI/2/72);
140 | mHeadEffect=new DashPathEffect(new float[]{padding*2,padding},0);
141 |
142 | faceMaxLROffset =bodyRadius/3;
143 | faceLROffset =-faceMaxLROffset;
144 | eyeRadius=eyeMaxRadius=bombLineWidth/2;
145 | eyeMinRadius=eyeMaxRadius/6;
146 |
147 | faceMaxTBOffset=bodyRadius/3;
148 | maxBlastCircleRadius = getMeasuredWidth()*(2);
149 |
150 | mouthMaxWidthOffset =bodyRadius/5-bodyRadius/5/10;
151 | mouthMaxHeightOffset =bodyRadius/5/2;
152 |
153 | mouthFSMaxWidthOffset= mouthMaxWidthOffset/3;
154 | mouthFSMaxHeightOffset = mouthMaxHeightOffset/2;
155 |
156 | bombCenterX=getMeasuredWidth()/2;
157 | bombCenterY=getMeasuredHeight()-bombLineWidth-bodyRadius;
158 |
159 | setHeadLinePath();
160 | setHeadPath();
161 | setBodyLightPath();
162 | }
163 |
164 | private void setBodyLightPath() {
165 | //160度坐标计算
166 | mBodyLightPath.reset();
167 | Point point=getPointInCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth,160);
168 | mBodyLightPath.moveTo(point.x-bodyRadius,point.y);
169 | mBodyLightPath.lineTo(point.x,point.y);
170 | Point pointControl=getPointInCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth+bombLineWidth*2.2f,210);
171 | point=getPointInCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth,260);
172 | mBodyLightPath.quadTo(pointControl.x,pointControl.y,point.x,point.y);
173 | mBodyLightPath.lineTo(point.x-bodyRadius,point.y);
174 | mBodyLightPath.close();
175 | }
176 |
177 | private void setHeadPath() {
178 | mHeadPath.reset();
179 | mHeadPath.moveTo(bombCenterX-bodyRadius/5,getMeasuredHeight()/2);
180 | mHeadPath.lineTo(bombCenterX+bodyRadius/5,getMeasuredHeight()/2);
181 | mHeadPath.lineTo(bombCenterX+bodyRadius/5,bombCenterY-bodyRadius-bodyRadius/4);
182 | mHeadPath.lineTo(bombCenterX,bombCenterY-bodyRadius-bodyRadius/4-bodyRadius/4/4);
183 | mHeadPath.lineTo(bombCenterX-bodyRadius/5,bombCenterY-bodyRadius-bodyRadius/4);
184 | mHeadPath.close();
185 | }
186 |
187 | private void setHeadLinePath() {
188 | float beginY=bombCenterY-bodyRadius-bodyRadius/4-bodyRadius/4/4;
189 | mHeadLinePath.reset();
190 | mHeadLinePath.moveTo(bombCenterX,beginY);
191 | float controlY=beginY-bodyRadius/2.2f;
192 | float bottomPointY=bombCenterY-bodyRadius;//转折点高度
193 | mHeadLinePath.quadTo(bombCenterX+bodyRadius/2/5,controlY,bombCenterX+bodyRadius/2,controlY);
194 | mHeadLinePath.cubicTo(bombCenterX+bodyRadius/2+bodyRadius/2/5*4,controlY
195 | ,bombCenterX+bodyRadius/2*2f-bodyRadius/16,bottomPointY-bodyRadius/6
196 | ,bombCenterX+bodyRadius/2*2f,bottomPointY);
197 | mHeadLinePath.quadTo(bombCenterX+bodyRadius/2*2f+bodyRadius/16,bottomPointY+bodyRadius/6
198 | ,bombCenterX+bodyRadius/2*2f+bodyRadius/7,bottomPointY+bodyRadius/4);
199 | }
200 |
201 | @Override
202 | protected void onDraw(Canvas canvas) {
203 | super.onDraw(canvas);
204 | drawHead(canvas);//头部小房子
205 | drawGround(canvas);//地板
206 | drawBody(canvas);//身体
207 | drawBodyBorder(canvas);//身体边框
208 | drawFace(canvas);//脸
209 | drawFaceShadow(canvas);//脸阴影
210 | drawHeadLine(canvas);//头部的炸弹线
211 | drawBlast(canvas);//爆炸
212 | }
213 |
214 | private void drawFaceShadow(Canvas canvas) {
215 | //两个圆相交产生阴影
216 | int save=canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
217 | mPaint.setStyle(Paint.Style.FILL);
218 | mPaint.setColor(bombShadowColor);
219 | canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
220 | mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
221 | canvas.translate(-bodyRadius/5,-bodyRadius/5);
222 | mPaint.setColor(bombColor);
223 | canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
224 | canvas.restoreToCount(save);
225 | mPaint.setXfermode(null);
226 | }
227 |
228 | private void drawFace(Canvas canvas) {
229 | canvas.save();
230 | mCamera.save();
231 | mCamera.rotate(bombTBRotate,0,-bombLRRotate/3);
232 | mMatrix.reset();
233 | mCamera.getMatrix(mMatrix);
234 | mCamera.restore();
235 | mMatrix.preTranslate(-bombCenterX,-(bombCenterY));
236 | mMatrix.postTranslate(bombCenterX,bombCenterY);
237 | mMatrix.postTranslate(faceLROffset,faceTBOffset);
238 | canvas.concat(mMatrix);
239 | //眼睛 椭圆控制
240 | mPaint.setStyle(Paint.Style.FILL);
241 | mPaint.setColor(bombLineColor);
242 | float eyeY=bombCenterY+bodyRadius/5;
243 | float eyeWidth=Math.max(eyeMaxRadius,eyeRadius);
244 | mRectF.set(bombCenterX-bodyRadius/3.5f-eyeWidth,eyeY-eyeRadius
245 | ,bombCenterX-bodyRadius/3.5f+eyeWidth,eyeY+eyeRadius);
246 | canvas.drawOval(mRectF,mPaint);
247 | mRectF.set(bombCenterX+bodyRadius/3.5f-eyeWidth,eyeY-eyeRadius
248 | ,bombCenterX+bodyRadius/3.5f+eyeWidth,eyeY+eyeRadius);
249 | canvas.drawOval(mRectF,mPaint);
250 | //画嘴巴 路径
251 | float mouthY=eyeY+bombLineWidth- mouthHeightOffset;//嘴巴起始高度
252 | float mouthMaxY=mouthY+bodyRadius/7+ mouthHeightOffset - mouthFSHeightOffset;//嘴巴最底部
253 | float mouthHalfDistance=bodyRadius/5-mouthWidthOffset*0.5f + mouthFSWidthOffset;//嘴巴顶部的拐角的一半宽度
254 | float mouthTopHalfDistance=(mouthHalfDistance-bodyRadius/5/10)-mouthWidthOffset; //嘴巴顶部的一半宽度
255 | float mouthHorDistanceHalf=(mouthMaxY-mouthY)/(6-4*mouthOffsetPercent);//嘴角控制点的距离嘴角点的竖直距离
256 | if (mouthTopHalfDistance0.65) {
312 | mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
313 | canvas.drawCircle(bombCenterX, circleY, currentBlastCircleRadius - maxBlastCircleRadius * 0.65f, mPaint);
314 | mPaint.setXfermode(null);
315 | }
316 | canvas.restoreToCount(save);
317 | }
318 |
319 | private void drawHeadLine(Canvas canvas) {
320 | canvas.save();
321 | mCamera.save();
322 | mCamera.rotate(bombTBRotate,0,-bombLRRotate);
323 | mMatrix.reset();
324 | mCamera.getMatrix(mMatrix);
325 | mCamera.restore();
326 | mMatrix.preTranslate(-bombCenterX,-bombCenterY);
327 | mMatrix.postTranslate(bombCenterX,bombCenterY);
328 | canvas.concat(mMatrix);
329 | mPaint.setColor(bombLineColor);
330 | mPaint.setStyle(Paint.Style.STROKE);
331 | mPathMeasure.setPath(mHeadLinePath,false);
332 | mPath.reset();
333 | mPathMeasure.getSegment(0,mPathMeasure.getLength()*headLinePercent,mPath,true);
334 | canvas.drawPath(mPath,mPaint);
335 | //火光
336 | mPathMeasure.setPath(mPath,false);
337 | float length=mPathMeasure.getLength();
338 | mPathMeasure.getPosTan(length,mPathPosition,null);
339 | mPaint.setColor(Color.parseColor("#fbb42d"));
340 | mPaint.setStyle(Paint.Style.FILL);
341 | canvas.drawCircle(mPathPosition[0],mPathPosition[1],Math.max(bombLineWidth/1.3f*headLineLightRate,bombLineWidth/2*1.2f),mPaint);
342 | mPaint.setColor(Color.parseColor("#f34671"));
343 | mPath.reset();
344 | mPath.addCircle(mPathPosition[0],mPathPosition[1],bombLineWidth/2.5f*headLineLightRate, Path.Direction.CCW);
345 | mPaint.setPathEffect(mHeadEffect);
346 | canvas.drawPath(mPath,mPaint);
347 | mPaint.setPathEffect(null);
348 | mPaint.setColor(Color.WHITE);
349 | canvas.drawCircle(mPathPosition[0],mPathPosition[1], bombLineWidth /6.5f * headLineLightRate,mPaint);
350 | canvas.restore();
351 | }
352 |
353 | private void drawHead(Canvas canvas) {
354 | canvas.save();
355 | mCamera.save();
356 | mCamera.rotate(bombTBRotate,0,-bombLRRotate);
357 | mMatrix.reset();
358 | mCamera.getMatrix(mMatrix);
359 | mCamera.restore();
360 | mMatrix.preTranslate(-bombCenterX,-(bombCenterY));
361 | mMatrix.postTranslate(bombCenterX,(bombCenterY));
362 | canvas.concat(mMatrix);
363 |
364 | mPaint.setStrokeWidth(bombLineWidth*0.8f);
365 | //内部
366 | mPaint.setColor(bombColor);
367 | mPaint.setStyle(Paint.Style.FILL);
368 | canvas.drawPath(mHeadPath,mPaint);
369 | //边框
370 | mPaint.setColor(bombLineColor);
371 | mPaint.setStyle(Paint.Style.STROKE);
372 | canvas.drawPath(mHeadPath,mPaint);
373 | mPaint.setStrokeWidth(bombLineWidth);
374 | canvas.restore();
375 | }
376 |
377 | private void drawBody(Canvas canvas) {
378 | mPaint.setStyle(Paint.Style.FILL);
379 | mPaint.setColor(bombColor);
380 | canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
381 | //左上角光点
382 | mPaint.setPathEffect(highLightPathEffect);
383 | mPaint.setColor(lightColor);
384 | mPaint.setStyle(Paint.Style.STROKE);
385 | mPath.reset();
386 | mPath.addCircle(bombCenterX,bombCenterY, highLightRadius, Path.Direction.CCW);
387 | canvas.drawPath(mPath,mPaint);
388 | //左上角的光边
389 | mPaint.setPathEffect(null);
390 | mRectF.set(bombCenterX-bodyRadius+bombLineWidth/2,bombCenterY-bodyRadius+bombLineWidth/2
391 | ,bombCenterX+bodyRadius-bombLineWidth/2,getMeasuredHeight()-bombLineWidth-bombLineWidth/2);
392 | canvas.drawArc(mRectF,160,100,false,mPaint);
393 | //拼接光边
394 | mPath.reset();
395 | mPath.addCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2, Path.Direction.CCW);
396 | canvas.save();
397 | canvas.clipPath(mPath);//裁剪圆内
398 |
399 | mPaint.setStyle(Paint.Style.FILL);
400 | mPaint.setColor(lightColor);
401 | canvas.drawPath(mBodyLightPath,mPaint);
402 | canvas.restore();
403 | }
404 |
405 |
406 | private Point getPointInCircle(int circleX,int circleY,float radius,float angle){
407 | Point mPoint=new Point();
408 | mPoint.set((int)(circleX + radius * Math.cos(Math.toRadians(angle))),
409 | (int)(circleY+radius*Math.sin(Math.toRadians(angle))));
410 | return mPoint;
411 | }
412 |
413 | private void drawBodyBorder(Canvas canvas) {
414 | canvas.save();
415 | canvas.rotate(bombLRRotate,bombCenterX,bombCenterY);
416 | mPaint.setPathEffect(bodyDashPathEffect);
417 | mPaint.setColor(bombLineColor);
418 | mPaint.setStyle(Paint.Style.STROKE);
419 | mPath.reset();
420 | mPath.addCircle(bombCenterX,bombCenterY,bodyRadius, Path.Direction.CW);
421 | canvas.drawPath(mPath,mPaint);
422 | canvas.restore();
423 | }
424 |
425 | private void drawGround(Canvas canvas) {
426 | mPaint.setStyle(Paint.Style.STROKE);
427 | mPaint.setColor(bombLineColor);
428 | mPaint.setPathEffect(groundDashPathEffect);
429 | mPath.reset();
430 | mPath.moveTo(bombLineWidth/2,getMeasuredHeight()-bombLineWidth/2);
431 | mPath.lineTo(getMeasuredWidth()-bombLineWidth/2,getMeasuredHeight()-bombLineWidth/2);
432 | canvas.drawPath(mPath,mPaint);
433 | }
434 |
435 | private AnimatorSet set=new AnimatorSet();
436 | public void startAnim(){
437 | stopAnim();
438 | ValueAnimator faceTBAnim=getFaceTopBottomAnim();
439 | ValueAnimator faceLRAnim=getFaceLeftRightAnim();
440 | AnimatorSet faceChangeAnim=getFaceChangeAnim();
441 | set.play(getBlastAnim()).after(faceChangeAnim);
442 | set.play(faceChangeAnim).after(faceTBAnim);
443 | set.play(faceTBAnim).after(faceLRAnim);
444 | set.play(faceLRAnim).with(getHeadLineAnim());
445 | set.start();
446 | }
447 |
448 | public void stopAnim(){
449 | set.cancel();
450 | initData();
451 | invalidate();
452 | }
453 |
454 | private void initData() {
455 | faceTBOffset=0;
456 | bombTBRotate=0;
457 | bombLRRotate=15;
458 | faceLROffset=-faceMaxLROffset;
459 | currentBlastCircleRadius =0;
460 | blastCircleRadiusPercent=0;
461 | eyeRadius=eyeMaxRadius;
462 | headLinePercent=1;
463 | mouthWidthOffset=0;
464 | mouthHeightOffset =0;
465 | mouthOffsetPercent=0;
466 | mouthFSWidthOffset=0;
467 | mouthFSHeightOffset=0;
468 | headLineLightRate=0;
469 | }
470 |
471 | private int getFaceChangeAnimTime(){
472 | return 450;
473 | }
474 |
475 | private AnimatorSet getFaceChangeAnim(){
476 | AnimatorSet animatorSet=new AnimatorSet();
477 | //眼睛
478 | ValueAnimator valueAnimator= ValueAnimator.ofFloat(1,0,1.4f)
479 | .setDuration(getFaceChangeAnimTime());
480 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
481 | @Override
482 | public void onAnimationUpdate(ValueAnimator animation) {
483 | eyeRadius=eyeMaxRadius*(float) animation.getAnimatedValue();
484 | if (eyeRadius0.75){//第一阶段还是第二阶段
498 | mouthWidthOffset=mouthMaxWidthOffset*value;
499 | mouthHeightOffset = mouthMaxHeightOffset *value;
500 | mouthOffsetPercent=animation.getAnimatedFraction();
501 | }else{
502 | mouthFSWidthOffset=mouthFSMaxWidthOffset*value;
503 | mouthFSHeightOffset=mouthFSMaxHeightOffset*value;
504 | }
505 | invalidate();
506 | }
507 | });
508 | animatorSet.play(valueAnimator).with(mouthAnimator);
509 | return animatorSet;
510 | }
511 |
512 | private int getFaceTopBottomAnimTime(){
513 | return 300;
514 | }
515 | private int getFaceTopBottomAnimDelayTime(){
516 | return 200;
517 | }
518 |
519 | private ValueAnimator getFaceTopBottomAnim(){
520 | ValueAnimator objectAnimator= ofFloat(0,1)
521 | .setDuration(getFaceTopBottomAnimTime());
522 | objectAnimator.setStartDelay(getFaceTopBottomAnimDelayTime());
523 | objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
524 | @Override
525 | public void onAnimationUpdate(ValueAnimator animation) {
526 | float value= (float) animation.getAnimatedValue();
527 | faceTBOffset= -faceMaxTBOffset*value;
528 | bombTBRotate= bombMaxTBRotate*value;
529 | invalidate();
530 | }
531 | });
532 | return objectAnimator;
533 | }
534 |
535 | private int getFaceLeftRightAnimTime(){
536 | return 1400;
537 | }
538 | private ValueAnimator getFaceLeftRightAnim(){
539 | ValueAnimator valueAnimator= ofFloat(-1,0,1,0)
540 | .setDuration(getFaceLeftRightAnimTime());
541 | valueAnimator.setInterpolator(new DecelerateInterpolator());
542 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
543 | @Override
544 | public void onAnimationUpdate(ValueAnimator animation) {
545 | float value= (float) animation.getAnimatedValue();
546 | faceLROffset = faceMaxLROffset *value;
547 | bombLRRotate = -bombMaxLRRotate *value;
548 | if (Math.abs(value)<0.3&&animation.getAnimatedFraction()<0.6){
549 | eyeRadius=Math.max(eyeMaxRadius*Math.abs(value),eyeMinRadius);
550 | }else{
551 | eyeRadius=eyeMaxRadius;
552 | }
553 | invalidate();
554 | }
555 | });
556 | return valueAnimator;
557 | }
558 |
559 | private int getHeadLineAnimTime(){
560 | return getFaceLeftRightAnimTime()+getFaceTopBottomAnimTime()+getFaceTopBottomAnimDelayTime()+getFaceChangeAnimTime()+500;
561 | }
562 | private AnimatorSet getHeadLineAnim(){
563 | AnimatorSet animatorSet=new AnimatorSet();
564 | ValueAnimator valueAnimator= ofFloat(1f,0f)
565 | .setDuration(getHeadLineAnimTime());
566 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
567 | @Override
568 | public void onAnimationUpdate(ValueAnimator animation) {
569 | headLinePercent= (float) animation.getAnimatedValue();
570 | invalidate();
571 | }
572 | });
573 | ValueAnimator valueAnimatorLight=ValueAnimator.ofFloat(0f,1.3f,0f)
574 | .setDuration(getHeadLineAnimTime()/5);
575 | valueAnimatorLight.setRepeatCount(5);
576 | valueAnimatorLight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
577 | @Override
578 | public void onAnimationUpdate(ValueAnimator animation) {
579 | headLineLightRate= (float) animation.getAnimatedValue();
580 | }
581 | });
582 | animatorSet.play(valueAnimator).with(valueAnimatorLight);
583 | return animatorSet;
584 | }
585 |
586 | private ValueAnimator getBlastAnim(){
587 | ValueAnimator valueAnimator= ofFloat(0,maxBlastCircleRadius)
588 | .setDuration(500);
589 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
590 | @Override
591 | public void onAnimationUpdate(ValueAnimator animation) {
592 | if (animation.getAnimatedFraction()>0.7f){
593 | initData();
594 | }
595 | currentBlastCircleRadius = (float) animation.getAnimatedValue();
596 | blastCircleRadiusPercent=animation.getAnimatedFraction();
597 | invalidate();
598 | }
599 | });
600 | valueAnimator.addListener(new AnimatorListenerAdapter() {
601 | @Override
602 | public void onAnimationEnd(Animator animation) {
603 | super.onAnimationEnd(animation);
604 | initData();
605 | invalidate();
606 | }
607 | });
608 | return valueAnimator;
609 | }
610 |
611 | private float getRadianLength(float angle,float radius){
612 | return (float) (angle*Math.PI*radius/180f);
613 | }
614 | }
615 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/jelly/JellyView.java:
--------------------------------------------------------------------------------
1 | package com.ivy.jelly;
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.os.Build;
9 | import android.support.annotation.Nullable;
10 | import android.support.annotation.RequiresApi;
11 | import android.util.AttributeSet;
12 | import android.view.View;
13 |
14 | /**
15 | * Created by ivy on 2017/9/19.
16 | * Description:
17 | */
18 |
19 | public class JellyView extends View {
20 | private Paint mPaint=new Paint();
21 | private Path mPath=new Path();
22 | private float centerX,centerY;
23 | private float width, height;
24 | public JellyView(Context context) {
25 | super(context);
26 | init();
27 | }
28 |
29 | public JellyView(Context context, @Nullable AttributeSet attrs) {
30 | super(context, attrs);
31 | init();
32 | }
33 |
34 | public JellyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
35 | super(context, attrs, defStyleAttr);
36 | init();
37 | }
38 |
39 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
40 | public JellyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
41 | super(context, attrs, defStyleAttr, defStyleRes);
42 | init();
43 | }
44 |
45 | @Override
46 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
47 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
48 | centerX=getMeasuredWidth()/2;
49 | centerY=getMeasuredHeight()/2;
50 | width=getMeasuredWidth();
51 | height =getMeasuredHeight();
52 | }
53 |
54 | @Override
55 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
56 | super.onSizeChanged(w, h, oldw, oldh);
57 | centerX=w/2;
58 | centerY=h/2;
59 | width=w;
60 | height=h;
61 | }
62 |
63 | public void init(){
64 | setBackgroundColor(Color.parseColor("#12092c"));
65 | mPaint.setColor(Color.parseColor("#00bbff"));
66 | mPaint.setAntiAlias(true);
67 | mPaint.setStyle(Paint.Style.FILL);
68 | }
69 |
70 | @Override
71 | protected void onDraw(Canvas canvas) {
72 | super.onDraw(canvas);
73 | drawHand(canvas);
74 | }
75 |
76 | private void drawHand(Canvas canvas) {
77 | mPath.reset();
78 | /*mPath.moveTo(centerX-getMeasuredWidth()/10,centerY);
79 | mPath.quadTo(centerX,centerY-getMeasuredWidth()/10,centerX+getMeasuredWidth()/10,centerY);*/
80 | mPath.moveTo(centerX,centerY);
81 | mPath.quadTo(centerX-width/20,centerY-width/20,centerX-width/18,centerY-width/20);
82 | mPath.close();
83 | canvas.drawPath(mPath,mPaint);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/jelly/MainJellyActivity.java:
--------------------------------------------------------------------------------
1 | package com.ivy.jelly;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | import com.ivy.weather.R;
8 |
9 | /**
10 | * Created by ivy on 2017/9/19.
11 | * Description:
12 | */
13 |
14 | public class MainJellyActivity extends AppCompatActivity {
15 | @Override
16 | protected void onCreate(@Nullable Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_jelly_main);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/main/IvyOnTouchListener.java:
--------------------------------------------------------------------------------
1 | package com.ivy.main;
2 |
3 | import android.content.Context;
4 | import android.graphics.Rect;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.GestureDetector;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 |
10 | /**
11 | * Created by ivy on 2017/9/27.
12 | * Description:
13 | */
14 |
15 | public abstract class IvyOnTouchListener extends RecyclerView.SimpleOnItemTouchListener {
16 | private RecyclerView mRecyclerView;
17 | private Context mContext;
18 |
19 | public IvyOnTouchListener(Context context){
20 | this.mContext=context;
21 | }
22 | private GestureDetector mGestureDetector=new GestureDetector(mContext,new GestureDetector.SimpleOnGestureListener(){
23 | @Override
24 | public boolean onSingleTapUp(MotionEvent e) {
25 | View childView = findChildViewUnder(e.getX(), e.getY());
26 | if (childView != null) {
27 | int position = mRecyclerView.getChildLayoutPosition(childView);
28 | onItemClick(position, childView);
29 | return true;
30 | }
31 |
32 | if (onEmptyClick(e)){
33 | return true;
34 | }
35 | return super.onSingleTapUp(e);
36 | }
37 | });
38 |
39 | public View findChildViewUnder(float x, float y) {
40 | final int count = mRecyclerView.getChildCount();
41 | Rect rect=new Rect();
42 | for (int i = count - 1; i >= 0; i--) {
43 | final View child = mRecyclerView.getChildAt(i);
44 | child.getHitRect(rect);
45 | if (rect.contains((int) x,(int) y)){
46 | return child;
47 | }
48 | }
49 | return null;
50 | }
51 |
52 | protected abstract boolean onEmptyClick(MotionEvent e);
53 |
54 |
55 | public abstract void onItemClick(int position, View childView);
56 |
57 | @Override
58 | public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
59 | mRecyclerView=rv;
60 | return mGestureDetector.onTouchEvent(e);
61 | }
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/main/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.ivy.main;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.LayoutInflater;
10 | import android.view.MotionEvent;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.TextView;
14 |
15 | import com.ivy.bomb.BombActivity;
16 | import com.ivy.ruler.RulerActivity;
17 | import com.ivy.weather.R;
18 | import com.ivy.weather.WeatherActivity;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * Created by ivy on 2017/10/25.
25 | * Description:
26 | */
27 |
28 | public class MainActivity extends AppCompatActivity {
29 | private RecyclerView rv;
30 | private List mData=new ArrayList<>();
31 | @Override
32 | protected void onCreate(@Nullable Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_main);
35 | addActivity();
36 | rv= (RecyclerView) this.findViewById(R.id.rv);
37 | rv.setLayoutManager(new LinearLayoutManager(this));
38 | rv.setAdapter(new MyAdapter());
39 | rv.addOnItemTouchListener(new IvyOnTouchListener(this) {
40 | @Override
41 | protected boolean onEmptyClick(MotionEvent e) {
42 | return false;
43 | }
44 |
45 | @Override
46 | public void onItemClick(int position, View childView) {
47 | Intent intent=new Intent(MainActivity.this,mData.get(position).getClazz());
48 | MainActivity.this.startActivity(intent);
49 | }
50 | });
51 | }
52 |
53 | private void addActivity() {
54 | mData.clear();
55 | mData.add(new ViewItem("天气小太阳", WeatherActivity.class));
56 | mData.add(new ViewItem("薄荷卷尺", RulerActivity.class));
57 | mData.add(new ViewItem("萌萌炸弹", BombActivity.class));
58 | }
59 |
60 | private class MyAdapter extends RecyclerView.Adapter{
61 | @Override
62 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
63 | return new ViewHolder(LayoutInflater.from(MainActivity.this).inflate(R.layout.adapter_main,parent,false));
64 | }
65 |
66 | @Override
67 | public void onBindViewHolder(ViewHolder holder, int position) {
68 | holder.tv.setText(mData.get(position).getText());
69 | }
70 |
71 | @Override
72 | public int getItemCount() {
73 | return mData.size();
74 | }
75 | }
76 |
77 | private class ViewHolder extends RecyclerView.ViewHolder{
78 | private TextView tv;
79 | public ViewHolder(View itemView) {
80 | super(itemView);
81 | tv= (TextView) itemView.findViewById(R.id.tv);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/main/ViewItem.java:
--------------------------------------------------------------------------------
1 | package com.ivy.main;
2 |
3 | import android.content.Intent;
4 |
5 | /**
6 | * Created by ivy on 2017/10/25.
7 | * Description:
8 | */
9 |
10 | public class ViewItem {
11 | private String text;
12 | private Class clazz;
13 |
14 | public ViewItem(String text, Class clazz) {
15 | this.text = text;
16 | this.clazz = clazz;
17 | }
18 |
19 | public String getText() {
20 |
21 | return text;
22 | }
23 |
24 | public void setText(String text) {
25 | this.text = text;
26 | }
27 |
28 | public Class getClazz() {
29 | return clazz;
30 | }
31 |
32 | public void setClazz(Class clazz) {
33 | this.clazz = clazz;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/ruler/RulerActivity.java:
--------------------------------------------------------------------------------
1 | package com.ivy.ruler;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | import com.ivy.weather.R;
8 |
9 | /**
10 | * Created by ivy on 2017/10/13.
11 | * Description:
12 | */
13 |
14 | public class RulerActivity extends AppCompatActivity {
15 | @Override
16 | protected void onCreate(@Nullable Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_ruler);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/ruler/ScrollerRulerView.java:
--------------------------------------------------------------------------------
1 | package com.ivy.ruler;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.os.Build;
8 | import android.support.annotation.Nullable;
9 | import android.support.annotation.RequiresApi;
10 | import android.util.AttributeSet;
11 | import android.util.TypedValue;
12 | import android.view.GestureDetector;
13 | import android.view.MotionEvent;
14 | import android.view.View;
15 | import android.view.ViewConfiguration;
16 | import android.view.animation.LinearInterpolator;
17 | import android.widget.Scroller;
18 | import java.text.DecimalFormat;
19 |
20 |
21 | /**
22 | * Created by ivy on 2017/10/13.
23 | * Description:
24 | */
25 |
26 | public class ScrollerRulerView extends View{
27 | private Paint mPaint;
28 | //刻度宽度,用于控制显示刻度的多少
29 | private int scaleWidth,scaleNum;
30 | //刻度高度
31 | private int minScaleHeight, maxScaleHeight ,selectScaleHeight;
32 | //颜色
33 | private int scaleColor,selectScaleColor,rulerColor;
34 | //刻度线的粗细
35 | private int scaleVerLineStroke, scaleHorLineStroke, ScaleHorLineEntireStroke, scaleHorLineSelectStroke;
36 | private int beginX=0;//滑动距离
37 | //刻度文字颜色
38 | private int scaleTextColor;
39 | //各个文字大小
40 | private float scaleTextSize,currentValueTextSize,currentValueUnitTextSize;
41 | //单位
42 | private String unit="KG";
43 | private GestureDetector mGestureDetector=new GestureDetector(getContext(),new GestureDetector.SimpleOnGestureListener(){
44 | @Override
45 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
46 | beginX-=distanceX;
47 | invalidate();
48 | return true;
49 | }
50 |
51 | @Override
52 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
53 | if (Math.abs(velocityX)> ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity()){
54 | mScroller.fling(beginX,0, (int) velocityX,0,beginX-getMeasuredWidth()*10,beginX+getMeasuredWidth()*10,0,0);
55 | invalidate();
56 | return true;
57 | }else{
58 | return false;
59 | }
60 | }
61 |
62 | @Override
63 | public boolean onSingleTapUp(MotionEvent e) {
64 | return super.onSingleTapUp(e);
65 | }
66 |
67 | });
68 |
69 | public ScrollerRulerView(Context context) {
70 | super(context);
71 | init();
72 | }
73 |
74 | public ScrollerRulerView(Context context, @Nullable AttributeSet attrs) {
75 | super(context, attrs);
76 | init();
77 | }
78 |
79 | public ScrollerRulerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
80 | super(context, attrs, defStyleAttr);
81 | init();
82 | }
83 |
84 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
85 | public ScrollerRulerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
86 | super(context, attrs, defStyleAttr, defStyleRes);
87 | init();
88 | }
89 |
90 | @Override
91 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
92 | super.onMeasure(widthMeasureSpec,heightMeasureSpec);
93 | int width=getMeasuredWidth();
94 | int height=getMeasuredHeight();
95 | int minWidth= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,120,getContext().getResources().getDisplayMetrics());
96 | int minHeight= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,80,getContext().getResources().getDisplayMetrics());
97 | setMeasuredDimension(Math.max(minWidth,width),Math.max(minHeight,height));
98 | }
99 |
100 | private void init() {
101 | mScroller=new Scroller(getContext(),new LinearInterpolator());
102 | mPaint=new Paint();
103 | mPaint.setAntiAlias(true);
104 | scaleTextSize=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getContext().getResources().getDisplayMetrics());
105 | currentValueTextSize=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,30,getContext().getResources().getDisplayMetrics());
106 | currentValueUnitTextSize=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,12,getContext().getResources().getDisplayMetrics());
107 | scaleVerLineStroke =2;
108 | scaleHorLineStroke =4;
109 | ScaleHorLineEntireStroke =6;
110 | scaleHorLineSelectStroke=8;
111 | rulerColor= Color.parseColor("#eeeeee");
112 | scaleColor= Color.parseColor("#aaaaaa");
113 | selectScaleColor=Color.parseColor("#00bbff");
114 | scaleTextColor=Color.parseColor("#000000");
115 | }
116 |
117 | @Override
118 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
119 | super.onSizeChanged(w, h, oldw, oldh);
120 | scaleWidth =w/40;
121 | selectScaleHeight = getMeasuredHeight()/4;
122 | maxScaleHeight =selectScaleHeight/8*7;
123 | minScaleHeight = (int) (selectScaleHeight/8*3.5f);
124 | scaleNum = w/scaleWidth/2+1;
125 | }
126 |
127 | @Override
128 | protected void onDraw(Canvas canvas) {
129 | super.onDraw(canvas);
130 | drawText(canvas);
131 | drawRuler(canvas);
132 | }
133 |
134 | private void drawRuler(Canvas canvas) {
135 | mPaint.setTextSize(scaleTextSize);
136 | //背景
137 | mPaint.setColor(rulerColor);
138 | canvas.drawRect(0,getMeasuredHeight()/2,getMeasuredWidth(),getMeasuredHeight(),mPaint);
139 | //横线
140 | mPaint.setColor(scaleColor);
141 | mPaint.setStrokeWidth(scaleVerLineStroke);
142 | canvas.drawLine(0,getMeasuredHeight()/2,getMeasuredWidth(),getMeasuredHeight()/2,mPaint);
143 | //刻度和刻度文字
144 | int afterX=getMeasuredWidth()/2+scaleWidth+beginX%scaleWidth;
145 | int afterValue=-beginX/scaleWidth+1;
146 | int previousX=getMeasuredWidth()/2+beginX%scaleWidth;
147 | int previousValue=-beginX/scaleWidth;
148 | for(int i=0;i scaleWidth / 2 ? (scaleWidth - Math.abs(beginX) % scaleWidth) * (beginX / Math.abs(beginX))
222 | : Math.abs(beginX) % scaleWidth * (-beginX / Math.abs(beginX));
223 | mScroller.startScroll(beginX, 0, dx, 0, 200);
224 | invalidate();
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/setting/SettingActivity.java:
--------------------------------------------------------------------------------
1 | package com.ivy.setting;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.pm.ShortcutInfo;
6 | import android.content.pm.ShortcutManager;
7 | import android.graphics.drawable.Icon;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.support.annotation.Nullable;
11 | import android.support.annotation.RequiresApi;
12 | import android.support.v7.app.AppCompatActivity;
13 |
14 | import com.ivy.weather.R;
15 |
16 | import java.util.ArrayList;
17 | import java.util.HashSet;
18 | import java.util.List;
19 | import java.util.Set;
20 |
21 | import static android.content.pm.ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION;
22 |
23 | /**
24 | * Created by ivy on 2017/9/22.
25 | * Description:
26 | */
27 |
28 | public class SettingActivity extends AppCompatActivity {
29 | @RequiresApi(api = Build.VERSION_CODES.N_MR1)
30 | @Override
31 | protected void onCreate(@Nullable Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.activity_setting);
34 | ShortcutManager shortCutManager = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE);
35 | //shortCutManager.removeAllDynamicShortcuts();
36 | Intent intent=new Intent();
37 | intent.setAction(Intent.ACTION_VIEW);
38 | intent.setClass(this,SettingActivity.class);
39 | Set category=new HashSet<>();
40 | category.add(SHORTCUT_CATEGORY_CONVERSATION);
41 | List shortCutList=new ArrayList<>();
42 | for(int i=0;i {
15 | private final CircleInfo mCircleInfo;
16 |
17 | public CircleTypeEvaluator(CircleInfo circleInfo) {
18 | this.mCircleInfo=circleInfo;
19 | }
20 |
21 | @Override
22 | public CircleInfo evaluate(float fraction, CircleInfo startValue, CircleInfo endValue) {
23 | float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
24 | float radius = startValue.getRadius() + fraction * (endValue.getRadius()-startValue.getRadius());
25 | mCircleInfo.setCircleInfo(mCircleInfo.getX(),y,radius);
26 | return mCircleInfo;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/weather/WeatherActivity.java:
--------------------------------------------------------------------------------
1 | package com.ivy.weather;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Button;
7 |
8 | public class WeatherActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_weather);
14 | final WeatherView weatherView = (WeatherView) this.findViewById(R.id.weather_view);
15 | Button button= (Button) this.findViewById(R.id.btn_start);
16 | weatherView.setOnClickListener(new View.OnClickListener() {
17 | @Override
18 | public void onClick(View v) {
19 | weatherView.startAnim();
20 | }
21 | });
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ivy/weather/WeatherView.java:
--------------------------------------------------------------------------------
1 | package com.ivy.weather;
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.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.LinearGradient;
10 | import android.graphics.Paint;
11 | import android.graphics.Path;
12 | import android.graphics.RectF;
13 | import android.graphics.Shader;
14 | import android.os.Build;
15 | import android.os.Handler;
16 | import android.support.annotation.RequiresApi;
17 | import android.util.AttributeSet;
18 | import android.view.View;
19 | import android.view.animation.AccelerateDecelerateInterpolator;
20 | import android.view.animation.DecelerateInterpolator;
21 | import android.view.animation.LinearInterpolator;
22 |
23 | import java.util.HashMap;
24 | import java.util.Iterator;
25 | import java.util.Map;
26 | import java.util.concurrent.ConcurrentHashMap;
27 |
28 | /**
29 | * Created by ivy on 2017/8/11.
30 | * Description:
31 | */
32 |
33 | public class WeatherView extends View {
34 | private Paint mPaint;
35 | private RectF mRectCenterArc;
36 | private RectF mRectOutSideArc;
37 | private RectF mRectFSunFlower;
38 | private RectF mRectFCloudShadow;
39 | private RectF mRectFSunShadow;
40 | private float minRingCenterWidth;
41 | private float ringWidth;
42 | private int ringColor=Color.parseColor("#ffcf45");
43 | private float centerArcAngle, centerArcEndAngle;
44 | private float outSideArcAngle,outSideArcStartAngle;
45 | private boolean isDrawArcLine=false;
46 | private boolean isDrawSun=false;
47 | private boolean isDrawRing=false;
48 | private boolean isDrawCloud=false;
49 | private boolean isDrawCloudShadow=false;
50 | private boolean isDrawSunShadow=false;
51 | private float sunWidth;
52 | private float finalSunWidth;
53 | private float maxSunFlowerWidth;
54 | private float sunRotateAngle=0;
55 | private int cloudShadowAlpha =0;
56 | private Path mPath;
57 | private Path mCloudShadowPath;
58 | //云朵的组成部分信息
59 | private CircleInfo mCircleInfoTopOne,mCircleInfoTopTwo,mCircleInfoBottomOne,mCircleInfoBottomTwo,mCircleInfoBottomThree;
60 | //太阳花朵,白云的Shade
61 | private LinearGradient mCloudLinearGradient,mFlowerLinearGradient,mFlowerRotateLinearGradient;
62 | private int cloudShadowColor=Color.parseColor("#bc9a31");
63 | private float sunShadowWidth, sunShadowHeight;
64 | private int sunShadowColor=Color.parseColor("#bac3c3");
65 | //存储所有动画的ValueAnimator方便管理
66 | private ConcurrentHashMap animMap=new ConcurrentHashMap<>();
67 | //动画是否开始
68 | private boolean isStart=false;
69 |
70 | public WeatherView(Context context) {
71 | super(context);
72 | init();
73 | }
74 |
75 | public WeatherView(Context context, AttributeSet attrs) {
76 | super(context, attrs);
77 | init();
78 | }
79 |
80 | public WeatherView(Context context, AttributeSet attrs, int defStyleAttr) {
81 | super(context, attrs, defStyleAttr);
82 | init();
83 | }
84 |
85 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
86 | public WeatherView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
87 | super(context, attrs, defStyleAttr, defStyleRes);
88 | init();
89 | }
90 |
91 | @Override
92 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
93 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
94 | int width=getMeasuredWidth();
95 | setMeasuredDimension(width, (int) (width*1.4f));
96 | }
97 |
98 | @Override
99 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
100 | super.onSizeChanged(w, h, oldw, oldh);
101 | }
102 |
103 | public void init(){
104 | mPaint=new Paint();
105 | mPaint.setDither(true);
106 | mPaint.setAntiAlias(true);
107 | mRectCenterArc=new RectF();
108 | mRectOutSideArc =new RectF();
109 | mRectFSunFlower =new RectF();
110 | mRectFCloudShadow =new RectF();
111 | mRectFSunShadow =new RectF();
112 | mPath=new Path();
113 | mCloudShadowPath =new Path();
114 | mCircleInfoTopOne=new CircleInfo();
115 | mCircleInfoTopTwo=new CircleInfo();
116 | mCircleInfoBottomOne=new CircleInfo();
117 | mCircleInfoBottomTwo=new CircleInfo();
118 | mCircleInfoBottomThree=new CircleInfo();
119 | }
120 |
121 | @Override
122 | protected void onDraw(Canvas canvas) {
123 | super.onDraw(canvas);
124 | if (isDrawRing)
125 | drawZoomRing(canvas);
126 | if (isDrawArcLine)
127 | drawArcLine(canvas);
128 | if (isDrawSun)
129 | drawSun(canvas);
130 | if (isDrawSunShadow)
131 | drawSunShadow(canvas);
132 | if (isDrawCloudShadow)
133 | drawCloudShadow(canvas);
134 | if (isDrawCloud)
135 | drawCloud(canvas);
136 | }
137 |
138 | private void drawSunShadow(Canvas canvas) {
139 | mPaint.setColor(sunShadowColor);
140 | mPaint.setStyle(Paint.Style.FILL);
141 | mRectFSunShadow.set(getMeasuredWidth()/2-sunShadowWidth/2,getMeasuredHeight()- sunShadowHeight,
142 | getMeasuredWidth()/2+sunShadowWidth/2,getMeasuredHeight());
143 | canvas.drawOval(mRectFSunShadow,mPaint);
144 | }
145 |
146 | private void drawCloudShadow(Canvas canvas) {
147 | mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
148 | mPaint.setColor(cloudShadowColor);
149 | mPaint.setAlpha(cloudShadowAlpha);
150 | canvas.save();
151 | canvas.clipRect(0,getMeasuredHeight()/2+getMeasuredWidth()/7f,getMeasuredWidth(),getMeasuredHeight());
152 | mRectFCloudShadow.set(getMeasuredWidth()/2-finalSunWidth/2,getMeasuredHeight()/2-finalSunWidth/2,getMeasuredWidth()/2+finalSunWidth/2,getMeasuredHeight()/2+finalSunWidth/2);
153 | mCloudShadowPath.reset();
154 | mCloudShadowPath.moveTo(mCircleInfoBottomOne.getX(),getMeasuredHeight()/2+getMeasuredWidth()/7f);
155 | mCloudShadowPath.arcTo(mRectFCloudShadow,15,45,false);
156 | canvas.drawPath(mCloudShadowPath,mPaint);
157 | canvas.restore();
158 | mPaint.setAlpha(255);
159 | }
160 |
161 | private void drawCloud(Canvas canvas) {
162 | mPath.reset();
163 | mPaint.setShader(mCloudLinearGradient);
164 | if (mCircleInfoBottomOne.isCanDraw())
165 | mPath.addCircle(mCircleInfoBottomOne.getX(),mCircleInfoBottomOne.getY(),mCircleInfoBottomOne.getRadius(), Path.Direction.CW);//左下1
166 | if (mCircleInfoBottomTwo.isCanDraw())
167 | mPath.addCircle(mCircleInfoBottomTwo.getX(),mCircleInfoBottomTwo.getY(),mCircleInfoBottomTwo.getRadius(), Path.Direction.CW);//底部2
168 | if (mCircleInfoBottomThree.isCanDraw())
169 | mPath.addCircle(mCircleInfoBottomThree.getX(),mCircleInfoBottomThree.getY(),mCircleInfoBottomThree.getRadius(), Path.Direction.CW);//底3
170 | if (mCircleInfoTopOne.isCanDraw())
171 | mPath.addCircle(mCircleInfoTopOne.getX(),mCircleInfoTopOne.getY(),mCircleInfoTopOne.getRadius(), Path.Direction.CW);//顶1
172 | if (mCircleInfoTopTwo.isCanDraw())
173 | mPath.addCircle(mCircleInfoTopTwo.getX(),mCircleInfoTopTwo.getY(),mCircleInfoTopTwo.getRadius(), Path.Direction.CW);//顶2
174 | canvas.save();
175 | canvas.clipRect(0,0,getMeasuredWidth(),getMeasuredHeight()/2+getMeasuredWidth()/7f);
176 | canvas.drawPath(mPath,mPaint);
177 | canvas.restore();
178 | mPaint.setShader(null);
179 | }
180 |
181 | private void drawSun(Canvas canvas) {
182 | mPaint.setStrokeWidth(0);
183 | mPaint.setStyle(Paint.Style.FILL);
184 | mPaint.setColor(ringColor);
185 | mPaint.setShader(mFlowerLinearGradient);
186 | canvas.save();
187 | canvas.rotate(sunRotateAngle,getMeasuredWidth()/2,getMeasuredHeight()/2);
188 | canvas.drawRect(mRectFSunFlower,mPaint);
189 | canvas.rotate(45,getMeasuredWidth()/2,getMeasuredHeight()/2);
190 | mPaint.setShader(mFlowerRotateLinearGradient);
191 | canvas.drawRect(mRectFSunFlower,mPaint);
192 | canvas.restore();
193 | mPaint.setShader(null);
194 | canvas.drawCircle(getMeasuredWidth()/2,getMeasuredHeight()/2,sunWidth/2,mPaint);
195 | }
196 |
197 | private void drawArcLine(Canvas canvas) {
198 | mPaint.setColor(ringColor);
199 | mPaint.setStyle(Paint.Style.STROKE);
200 | mPaint.setStrokeCap(Paint.Cap.ROUND);
201 | mPaint.setStrokeWidth(getMeasuredWidth()/40);
202 | canvas.drawArc(mRectCenterArc, centerArcEndAngle-centerArcAngle,centerArcAngle,false,mPaint);
203 | mPaint.setStrokeWidth(getMeasuredWidth()/25);
204 | canvas.drawArc(mRectOutSideArc,outSideArcStartAngle,outSideArcAngle,false,mPaint);
205 | }
206 |
207 | private void drawZoomRing(Canvas canvas) {
208 | mPaint.setShader(null);
209 | mPaint.setStrokeWidth(0);
210 | mPaint.setStyle(Paint.Style.FILL);
211 | mPaint.setColor(ringColor);
212 | canvas.drawCircle(getMeasuredWidth()/2,getMeasuredHeight()/2,ringWidth/2,mPaint);
213 | mPaint.setColor(Color.WHITE);
214 | canvas.drawCircle(getMeasuredWidth()/2,getMeasuredHeight()/2,minRingCenterWidth/2,mPaint);
215 | }
216 |
217 | public void startAnim() {
218 | resetAnim();
219 | startInvalidateAnim();
220 | }
221 |
222 | private static final String ANIM_CONTROL_INVALIDATE="anim_control_invalidate";
223 | private void startInvalidateAnim() {
224 | isStart=true;
225 | ValueAnimator valueAnimator=animMap.get(ANIM_CONTROL_INVALIDATE);
226 | if (valueAnimator==null){
227 | valueAnimator=ValueAnimator.ofFloat(0,1);
228 | valueAnimator.setInterpolator(new LinearInterpolator());
229 | valueAnimator.setDuration(300);
230 | valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
231 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
232 | @Override
233 | public void onAnimationUpdate(ValueAnimator animation) {
234 | invalidate();
235 | }
236 | });
237 | valueAnimator.addListener(new AnimatorListenerAdapter() {
238 | @Override
239 | public void onAnimationStart(Animator animation) {
240 | super.onAnimationStart(animation);
241 | startRing();
242 | }
243 | });
244 | animMap.put(ANIM_CONTROL_INVALIDATE,valueAnimator);
245 | }
246 | startValueAnimator(valueAnimator);
247 | }
248 |
249 |
250 | public static final String ANIM_CLOUD_TOP_ONE="anim_cloud_top_one";
251 | public static final String ANIM_CLOUD_TOP_TWO="anim_cloud_top_two";
252 | public static final String ANIM_CLOUD_BOTTOM_ONE="anim_cloud_bottom_one";
253 | public static final String ANIM_CLOUD_BOTTOM_TWO="anim_cloud_bottom_two";
254 | public static final String ANIM_CLOUD_BOTTOM_THREE="anim_cloud_bottom_three";
255 | public void startCloud(){
256 | isDrawCloud=true;
257 | startCloudTemplate(ANIM_CLOUD_BOTTOM_ONE,0,mCircleInfoBottomOne);
258 | startCloudTemplate(ANIM_CLOUD_BOTTOM_TWO,200,mCircleInfoBottomTwo);
259 | startCloudTemplate(ANIM_CLOUD_BOTTOM_THREE,450,mCircleInfoBottomThree);
260 | startCloudTemplate(ANIM_CLOUD_TOP_ONE,300,mCircleInfoTopOne);
261 | startCloudTemplate(ANIM_CLOUD_TOP_TWO,350,mCircleInfoTopTwo);
262 | this.postDelayed(new Runnable() {
263 | @Override
264 | public void run() {
265 | startCloudShadow();
266 | }
267 | },600);
268 | }
269 |
270 | private void startCloudTemplate(String mapTag, long delay, final CircleInfo circleInfo){
271 | ValueAnimator valueAnimator=animMap.get(mapTag);
272 | if (valueAnimator==null){
273 | valueAnimator=ValueAnimator.ofObject(new CircleTypeEvaluator(circleInfo),new CircleInfo(circleInfo.getX(),circleInfo.getY()+circleInfo.getRadius(),0)
274 | ,new CircleInfo(circleInfo.getX(),circleInfo.getY(),circleInfo.getRadius()));
275 | valueAnimator.setDuration(600);
276 | valueAnimator.addListener(new AnimatorListenerAdapter() {
277 | @Override
278 | public void onAnimationStart(Animator animation) {
279 | super.onAnimationStart(animation);
280 | circleInfo.setCanDraw(true);
281 | }
282 | });
283 | animMap.put(mapTag,valueAnimator);
284 | }
285 | valueAnimator.setObjectValues(new CircleInfo(circleInfo.getX(),circleInfo.getY()+circleInfo.getRadius(),0)
286 | ,new CircleInfo(circleInfo.getX(),circleInfo.getY(),circleInfo.getRadius()));
287 | valueAnimator.setStartDelay(delay);
288 | startValueAnimator(valueAnimator);
289 | }
290 |
291 | public static final String ANIM_CLOUD_SHADOW="anim_cloud_shadow";
292 | private void startCloudShadow() {
293 | isDrawCloudShadow=true;
294 | ValueAnimator valueAnimator=animMap.get(ANIM_CLOUD_SHADOW);
295 | if (valueAnimator==null){
296 | valueAnimator=ValueAnimator.ofInt(0,255).setDuration(600);
297 | valueAnimator.setInterpolator(new LinearInterpolator());
298 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
299 | @Override
300 | public void onAnimationUpdate(ValueAnimator animation) {
301 | cloudShadowAlpha= (int) animation.getAnimatedValue();
302 | }
303 | });
304 | animMap.put(ANIM_CLOUD_SHADOW,valueAnimator);
305 | }
306 | startValueAnimator(valueAnimator);
307 | }
308 |
309 | public static final String ANIM_SUN_ZOOM="anim_sun_zoom";
310 | public static final String ANIM_FLOWER_ZOOM="anim_flower_zoom";
311 | private void startSun() {
312 | isDrawSun=true;
313 | //太阳内部圆
314 | ValueAnimator sunAnim= animMap.get(ANIM_SUN_ZOOM);
315 | if (sunAnim==null){
316 | sunAnim=ValueAnimator.ofFloat().setDuration(400);
317 | sunAnim.setInterpolator(new AccelerateDecelerateInterpolator());
318 | sunAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
319 | @Override
320 | public void onAnimationUpdate(ValueAnimator animation) {
321 | sunWidth= (float) animation.getAnimatedValue();
322 | }
323 | });
324 | animMap.put(ANIM_SUN_ZOOM,sunAnim);
325 | }
326 | sunAnim.setFloatValues(sunWidth,getMeasuredWidth(),finalSunWidth);
327 | startValueAnimator(sunAnim);
328 | //太阳光环
329 | ValueAnimator flowerAnim= animMap.get(ANIM_FLOWER_ZOOM);
330 | if (flowerAnim==null){
331 | flowerAnim=ValueAnimator.ofFloat().setDuration(400);
332 | flowerAnim.setInterpolator(new AccelerateDecelerateInterpolator());
333 | flowerAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
334 | @Override
335 | public void onAnimationUpdate(ValueAnimator animation) {
336 | float width= (float) animation.getAnimatedValue();
337 | mRectFSunFlower.set(getMeasuredWidth()/2f-width/2,getMeasuredHeight()/2f-width/2
338 | ,getMeasuredWidth()/2f+width/2,getMeasuredHeight()/2f+width/2);
339 | }
340 | });
341 | flowerAnim.addListener(new AnimatorListenerAdapter() {
342 | @Override
343 | public void onAnimationEnd(Animator animation) {
344 | super.onAnimationEnd(animation);
345 | startSunRotate();
346 | }
347 | });
348 | flowerAnim.setStartDelay(100);
349 | animMap.put(ANIM_FLOWER_ZOOM,flowerAnim);
350 | }
351 | flowerAnim.setFloatValues(0,maxSunFlowerWidth,maxSunFlowerWidth*0.9f);
352 | startValueAnimator(flowerAnim);
353 | this.postDelayed(new Runnable() {
354 | @Override
355 | public void run() {
356 | startCloud();
357 | }
358 | },300);
359 |
360 | this.postDelayed(new Runnable() {
361 | @Override
362 | public void run() {
363 | startSunShadow();
364 | }
365 | },200);
366 | }
367 |
368 | public static final String ANIM_WEATHER_SHADOW ="anim_weather_shadow";
369 | private void startSunShadow() {
370 | isDrawSunShadow=true;
371 | ValueAnimator valueAnimator=animMap.get(ANIM_WEATHER_SHADOW);
372 | if (valueAnimator==null){
373 | valueAnimator=ValueAnimator.ofFloat().setDuration(400);
374 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
375 | @Override
376 | public void onAnimationUpdate(ValueAnimator animation) {
377 | sunShadowWidth= (float) animation.getAnimatedValue();
378 | }
379 | });
380 | animMap.put(ANIM_WEATHER_SHADOW,valueAnimator);
381 | }
382 | valueAnimator.setFloatValues(0,getMeasuredWidth(),getMeasuredWidth()*0.8f);
383 | startValueAnimator(valueAnimator);
384 | }
385 |
386 | public static final String ANIM_SUN_ROTATE="anim_sun_rotate";
387 | private void startSunRotate() {
388 | ValueAnimator rotateAnim=animMap.get(ANIM_SUN_ROTATE);
389 | if (rotateAnim==null){
390 | rotateAnim =ValueAnimator.ofFloat(0,360f).setDuration(30*1000);
391 | rotateAnim.setRepeatCount(ValueAnimator.INFINITE);
392 | rotateAnim.setInterpolator(new LinearInterpolator());
393 | rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
394 | @Override
395 | public void onAnimationUpdate(ValueAnimator animation) {
396 | sunRotateAngle= (float) animation.getAnimatedValue();
397 | }
398 | });
399 | animMap.put(ANIM_SUN_ROTATE,rotateAnim);
400 | }
401 | startValueAnimator(rotateAnim);
402 | }
403 |
404 | public static final String ANIM_ARC_LINE_CENTER_ANGLE="anim_arc_line_center_angle";
405 | public static final String ANIM_ARC_LINE_CENTER_MOVE ="anim_arc_line_center_move";
406 | public static final String ANIM_ARC_LINE_OUTSIZE_ANGLE="anim_arc_line_outsize_angle";
407 | public static final String ANIM_ARC_LINE_OUTSIZE_MOVE ="anim_arc_line_outsize_move";
408 | private void startArcLine() {
409 | isDrawArcLine=true;
410 | //内部圆弧长度控制
411 | ValueAnimator centerArcLineAngleAnim= animMap.get(ANIM_ARC_LINE_CENTER_ANGLE);
412 | if (centerArcLineAngleAnim==null){
413 | centerArcLineAngleAnim=ValueAnimator.ofFloat().setDuration(500);
414 | centerArcLineAngleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
415 | @Override
416 | public void onAnimationUpdate(ValueAnimator animation) {
417 | centerArcAngle= (float) animation.getAnimatedValue();
418 | }
419 | });
420 | animMap.put(ANIM_ARC_LINE_CENTER_ANGLE,centerArcLineAngleAnim);
421 | }
422 | centerArcLineAngleAnim.setFloatValues(centerArcAngle,180,0);
423 | startValueAnimator(centerArcLineAngleAnim);
424 | //内部圆弧移动控制
425 | ValueAnimator centerArcLineMoveAnim= animMap.get(ANIM_ARC_LINE_CENTER_MOVE);
426 | if (centerArcLineMoveAnim==null){
427 | centerArcLineMoveAnim=ValueAnimator.ofFloat().setDuration(400);
428 | centerArcLineMoveAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
429 | @Override
430 | public void onAnimationUpdate(ValueAnimator animation) {
431 | centerArcEndAngle = (float) animation.getAnimatedValue();
432 | }
433 | });
434 | centerArcLineMoveAnim.addListener(new AnimatorListenerAdapter() {
435 | @Override
436 | public void onAnimationEnd(Animator animation) {
437 | super.onAnimationEnd(animation);
438 | isDrawArcLine=false;
439 | }
440 | });
441 | animMap.put(ANIM_ARC_LINE_CENTER_MOVE,centerArcLineMoveAnim);
442 | }
443 | centerArcLineMoveAnim.setFloatValues(centerArcEndAngle,630);
444 | startValueAnimator(centerArcLineMoveAnim);
445 | //外部圆弧长度控制
446 | ValueAnimator outSizeArcLineAngleAnim= animMap.get(ANIM_ARC_LINE_OUTSIZE_ANGLE);
447 | if (outSizeArcLineAngleAnim==null){
448 | outSizeArcLineAngleAnim=ValueAnimator.ofFloat().setDuration(400);
449 | outSizeArcLineAngleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
450 | @Override
451 | public void onAnimationUpdate(ValueAnimator animation) {
452 | outSideArcAngle= (float) animation.getAnimatedValue();
453 | }
454 | });
455 | animMap.put(ANIM_ARC_LINE_OUTSIZE_ANGLE,outSizeArcLineAngleAnim);
456 | }
457 | outSizeArcLineAngleAnim.setFloatValues(outSideArcAngle,180,0);
458 | startValueAnimator(outSizeArcLineAngleAnim);
459 | //外部圆弧移动控制
460 | ValueAnimator outSizeArcLineMoveAnim= animMap.get(ANIM_ARC_LINE_OUTSIZE_MOVE);
461 | if (outSizeArcLineMoveAnim==null){
462 | outSizeArcLineMoveAnim=ValueAnimator.ofFloat().setDuration(300);
463 | outSizeArcLineMoveAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
464 | @Override
465 | public void onAnimationUpdate(ValueAnimator animation) {
466 | outSideArcStartAngle= (float) animation.getAnimatedValue();
467 | }
468 | });
469 | animMap.put(ANIM_ARC_LINE_OUTSIZE_MOVE,outSizeArcLineMoveAnim);
470 | }
471 | outSizeArcLineMoveAnim.setFloatValues(outSideArcStartAngle,-90);
472 | startValueAnimator(outSizeArcLineMoveAnim);
473 | this.postDelayed(new Runnable() {
474 | @Override
475 | public void run() {
476 | startSun();
477 | }
478 | },250);
479 | }
480 |
481 | public static final String ANIM_RING_ZOOM="anim_ring_zoom";
482 | public static final String ANIM_RING_CIRCLE_ZOOM="anim_ring_circle_zoom";
483 | private void startRing() {
484 | isDrawRing=true;
485 | ValueAnimator zoomAnim= animMap.get(ANIM_RING_ZOOM);
486 | if (zoomAnim==null){
487 | zoomAnim= ValueAnimator.ofFloat().setDuration(500);
488 | zoomAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
489 | @Override
490 | public void onAnimationUpdate(ValueAnimator animation) {
491 | ringWidth= (float) animation.getAnimatedValue();
492 | }
493 | });
494 | zoomAnim.addListener(new AnimatorListenerAdapter() {
495 | @Override
496 | public void onAnimationEnd(Animator animation) {
497 | super.onAnimationEnd(animation);
498 | startArcLine();
499 | }
500 | });
501 | animMap.put(ANIM_RING_ZOOM,zoomAnim);
502 | }
503 | zoomAnim.setFloatValues(ringWidth,getMeasuredWidth()*0.8f);
504 | startValueAnimator(zoomAnim);
505 |
506 | ValueAnimator circleZoom= animMap.get(ANIM_RING_CIRCLE_ZOOM);
507 | if (circleZoom==null){
508 | circleZoom=ValueAnimator.ofFloat().setDuration(300);
509 | circleZoom.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
510 | @Override
511 | public void onAnimationUpdate(ValueAnimator animation) {
512 | minRingCenterWidth= (float) animation.getAnimatedValue();
513 | }
514 | });
515 | circleZoom.setStartDelay(300);
516 | circleZoom.addListener(new AnimatorListenerAdapter() {
517 | @Override
518 | public void onAnimationEnd(Animator animation) {
519 | super.onAnimationEnd(animation);
520 | isDrawRing=false;
521 | }
522 | });
523 | animMap.put(ANIM_RING_CIRCLE_ZOOM,circleZoom);
524 | }
525 | circleZoom.setFloatValues(minRingCenterWidth,getMeasuredWidth()*0.8f);
526 | startValueAnimator(circleZoom);
527 | }
528 |
529 | private void startValueAnimator(ValueAnimator valueAnimator){
530 | if (isStart) {
531 | valueAnimator.start();
532 | }
533 | }
534 |
535 | private void resetAnim() {
536 | stopAnimAndRemoveCallbacks();
537 | //是否画相应的内容
538 | isDrawArcLine=false;
539 | isDrawSun=false;
540 | isDrawRing=false;
541 | isDrawCloud=false;
542 | isDrawCloudShadow=false;
543 | isDrawSunShadow=false;
544 | //圆环部分
545 | minRingCenterWidth=10;
546 | ringWidth=3*minRingCenterWidth;
547 | //圆弧部分
548 | centerArcAngle=2;
549 | centerArcEndAngle =270+centerArcAngle;
550 | outSideArcStartAngle=180;
551 | outSideArcAngle=90;
552 | mRectCenterArc.set(getMeasuredWidth()/2-getMeasuredWidth()/6,getMeasuredHeight()/2-getMeasuredWidth()/6
553 | ,getMeasuredWidth()/2+getMeasuredWidth()/6,getMeasuredHeight()/2+getMeasuredWidth()/6);
554 | mRectOutSideArc.set(getMeasuredWidth()/2-getMeasuredWidth()/4,getMeasuredHeight()/2-getMeasuredWidth()/4
555 | ,getMeasuredWidth()/2+getMeasuredWidth()/4,getMeasuredHeight()/2+getMeasuredWidth()/4);
556 |
557 | //整个天气View的阴影
558 | sunShadowHeight =getMeasuredWidth()/25;
559 | //太阳旋转
560 | sunRotateAngle=0;
561 | //太阳出现
562 | sunWidth=0;
563 | finalSunWidth =getMeasuredWidth()*0.7f;
564 | maxSunFlowerWidth= (float) Math.sqrt(Math.pow(getMeasuredWidth()/2.0f,2)*2);
565 | mRectFSunFlower.set(0,0,0,0);
566 | mFlowerLinearGradient=new LinearGradient(getMeasuredWidth()/2-maxSunFlowerWidth/2,getMeasuredHeight()/2-maxSunFlowerWidth/2,
567 | getMeasuredWidth()/2+maxSunFlowerWidth/2,getMeasuredHeight()/2+maxSunFlowerWidth/2,
568 | new int[]{Color.parseColor("#fff38e"),Color.parseColor("#ebb228") ,Color.parseColor("#ae8200")},new float[]{0,0.5f,1}, Shader.TileMode.REPEAT);
569 | mFlowerRotateLinearGradient=new LinearGradient(getMeasuredWidth()/2-maxSunFlowerWidth/2,getMeasuredHeight()/2-maxSunFlowerWidth/2,
570 | getMeasuredWidth()/2+maxSunFlowerWidth/2,getMeasuredHeight()/2-maxSunFlowerWidth/2,
571 | Color.parseColor("#f7b600") ,Color.parseColor("#ae8200"), Shader.TileMode.REPEAT);
572 | //云
573 | mCircleInfoBottomOne.setCircleInfo(getMeasuredWidth()/2,getMeasuredHeight()/2+getMeasuredWidth()/10,getMeasuredWidth()/10,false);//左下1
574 | mCircleInfoTopOne.setCircleInfo(getMeasuredWidth()/2+getMeasuredWidth()/14,getMeasuredHeight()/2-getMeasuredWidth()/30,getMeasuredWidth()/9,false);//顶1
575 | mCircleInfoBottomTwo.setCircleInfo(getMeasuredWidth()/2+getMeasuredWidth()/10*1.8f,getMeasuredHeight()/2+getMeasuredWidth()/10,getMeasuredWidth()/9,false);//底部2
576 | mCircleInfoTopTwo.setCircleInfo(getMeasuredWidth()/2+getMeasuredWidth()/10*2.2f,getMeasuredHeight()/2-getMeasuredWidth()/120,getMeasuredWidth()/10,false);//顶2
577 | mCircleInfoBottomThree.setCircleInfo(getMeasuredWidth()/2+getMeasuredWidth()/10*3.5f,getMeasuredHeight()/2+getMeasuredWidth()/10,getMeasuredWidth()/12,false);//底3
578 | mCloudLinearGradient =new LinearGradient(mCircleInfoBottomOne.getX()-mCircleInfoBottomOne.getRadius(),mCircleInfoTopOne.getY()-mCircleInfoTopOne.getRadius(),getMeasuredWidth(),getMeasuredHeight()/2+getMeasuredWidth()/7f,
579 | new int[]{Color.parseColor("#fcfbf3"),Color.parseColor("#efebdf") ,Color.parseColor("#d7d7c7")},new float[]{0,0.5f,1}, Shader.TileMode.REPEAT);
580 | //云阴影
581 | cloudShadowAlpha=0;
582 | invalidate();
583 | }
584 |
585 | @Override
586 | protected void onDetachedFromWindow() {
587 | super.onDetachedFromWindow();
588 | stopAnimAndRemoveCallbacks();
589 | }
590 |
591 | private void stopAnimAndRemoveCallbacks(){
592 | isStart=false;
593 | for (Map.Entry entry : animMap.entrySet()) {
594 | entry.getValue().end();
595 | }
596 | Handler handler=this.getHandler();
597 | if (handler!=null){
598 | handler.removeCallbacksAndMessages(null);
599 | }
600 | }
601 | }
602 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/a.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengivy/Weather/93bf44c991ea3068e4db3917a0de9920fd7b4868/app/src/main/res/drawable/a.gif
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_bomb.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_jelly_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_ruler.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_weather.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
20 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/adapter_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengivy/Weather/93bf44c991ea3068e4db3917a0de9920fd7b4868/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengivy/Weather/93bf44c991ea3068e4db3917a0de9920fd7b4868/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengivy/Weather/93bf44c991ea3068e4db3917a0de9920fd7b4868/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengivy/Weather/93bf44c991ea3068e4db3917a0de9920fd7b4868/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengivy/Weather/93bf44c991ea3068e4db3917a0de9920fd7b4868/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 好玩的View
3 | short title
4 | long title
5 | can not use
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/shortcuts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/test/java/com/ivy/weather/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ivy.weather;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/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.2.3'
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 |
--------------------------------------------------------------------------------
/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 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengivy/Weather/93bf44c991ea3068e4db3917a0de9920fd7b4868/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------