├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── frogermcs
│ │ └── io
│ │ └── likeanimation
│ │ ├── CircleView.java
│ │ ├── DotsView.java
│ │ ├── LikeButtonView.java
│ │ ├── MainActivity.java
│ │ └── Utils.java
│ └── res
│ ├── drawable-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_star_rate_off.png
│ └── ic_star_rate_on.png
│ ├── layout
│ ├── activity_main.xml
│ └── view_like_button.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | *.iml
8 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LikeAnimation
2 | Android button with delightful like animation inspired by Twitter's heart.
3 |
4 | 
5 |
6 | This is an example code described in blog post: Twitter's like animation in Android - alternative.
7 |
8 | [](http://www.youtube.com/watch?v=EdZjYTbRNuA)
9 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.1"
6 |
7 | defaultConfig {
8 | applicationId "frogermcs.io.likeanim"
9 | minSdkVersion 21
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:23.1.1'
25 | compile 'com.jakewharton:butterknife:7.0.1'
26 | }
27 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\AndroidSDK/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/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/frogermcs/io/likeanimation/CircleView.java:
--------------------------------------------------------------------------------
1 | package frogermcs.io.likeanimation;
2 |
3 | import android.animation.ArgbEvaluator;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Paint;
8 | import android.graphics.PorterDuff;
9 | import android.graphics.PorterDuffXfermode;
10 | import android.util.AttributeSet;
11 | import android.util.Property;
12 | import android.view.View;
13 |
14 | /**
15 | * Created by Miroslaw Stanek on 21.12.2015.
16 | */
17 | public class CircleView extends View {
18 | private static final int START_COLOR = 0xFFFF5722;
19 | private static final int END_COLOR = 0xFFFFC107;
20 |
21 | private ArgbEvaluator argbEvaluator = new ArgbEvaluator();
22 |
23 | private Paint circlePaint = new Paint();
24 | private Paint maskPaint = new Paint();
25 |
26 | private Bitmap tempBitmap;
27 | private Canvas tempCanvas;
28 |
29 | private float outerCircleRadiusProgress = 0f;
30 | private float innerCircleRadiusProgress = 0f;
31 |
32 | private int maxCircleSize;
33 |
34 | public CircleView(Context context) {
35 | super(context);
36 | init();
37 | }
38 |
39 | public CircleView(Context context, AttributeSet attrs) {
40 | super(context, attrs);
41 | init();
42 | }
43 |
44 | public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
45 | super(context, attrs, defStyleAttr);
46 | init();
47 | }
48 |
49 | public CircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
50 | super(context, attrs, defStyleAttr, defStyleRes);
51 | init();
52 | }
53 |
54 | private void init() {
55 | circlePaint.setStyle(Paint.Style.FILL);
56 | maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
57 | }
58 |
59 | @Override
60 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
61 | super.onSizeChanged(w, h, oldw, oldh);
62 | maxCircleSize = w / 2;
63 | tempBitmap = Bitmap.createBitmap(getWidth(), getWidth(), Bitmap.Config.ARGB_8888);
64 | tempCanvas = new Canvas(tempBitmap);
65 | }
66 |
67 | @Override
68 | protected void onDraw(Canvas canvas) {
69 | super.onDraw(canvas);
70 | tempCanvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR);
71 | tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, circlePaint);
72 | tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress * maxCircleSize, maskPaint);
73 | canvas.drawBitmap(tempBitmap, 0, 0, null);
74 | }
75 |
76 | public void setInnerCircleRadiusProgress(float innerCircleRadiusProgress) {
77 | this.innerCircleRadiusProgress = innerCircleRadiusProgress;
78 | postInvalidate();
79 | }
80 |
81 | public float getInnerCircleRadiusProgress() {
82 | return innerCircleRadiusProgress;
83 | }
84 |
85 | public void setOuterCircleRadiusProgress(float outerCircleRadiusProgress) {
86 | this.outerCircleRadiusProgress = outerCircleRadiusProgress;
87 | updateCircleColor();
88 | postInvalidate();
89 | }
90 |
91 | private void updateCircleColor() {
92 | float colorProgress = (float) Utils.clamp(outerCircleRadiusProgress, 0.5, 1);
93 | colorProgress = (float) Utils.mapValueFromRangeToRange(colorProgress, 0.5f, 1f, 0f, 1f);
94 | this.circlePaint.setColor((Integer) argbEvaluator.evaluate(colorProgress, START_COLOR, END_COLOR));
95 | }
96 |
97 | public float getOuterCircleRadiusProgress() {
98 | return outerCircleRadiusProgress;
99 | }
100 |
101 | public static final Property INNER_CIRCLE_RADIUS_PROGRESS =
102 | new Property(Float.class, "innerCircleRadiusProgress") {
103 | @Override
104 | public Float get(CircleView object) {
105 | return object.getInnerCircleRadiusProgress();
106 | }
107 |
108 | @Override
109 | public void set(CircleView object, Float value) {
110 | object.setInnerCircleRadiusProgress(value);
111 | }
112 | };
113 |
114 | public static final Property OUTER_CIRCLE_RADIUS_PROGRESS =
115 | new Property(Float.class, "outerCircleRadiusProgress") {
116 | @Override
117 | public Float get(CircleView object) {
118 | return object.getOuterCircleRadiusProgress();
119 | }
120 |
121 | @Override
122 | public void set(CircleView object, Float value) {
123 | object.setOuterCircleRadiusProgress(value);
124 | }
125 | };
126 | }
127 |
--------------------------------------------------------------------------------
/app/src/main/java/frogermcs/io/likeanimation/DotsView.java:
--------------------------------------------------------------------------------
1 | package frogermcs.io.likeanimation;
2 |
3 | import android.animation.ArgbEvaluator;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.util.AttributeSet;
8 | import android.util.Property;
9 | import android.view.View;
10 |
11 | /**
12 | * Created by Miroslaw Stanek on 20.12.2015.
13 | */
14 | public class DotsView extends View {
15 | private static final int DOTS_COUNT = 7;
16 | private static final int OUTER_DOTS_POSITION_ANGLE = 51;
17 |
18 | private static final int COLOR_1 = 0xFFFFC107;
19 | private static final int COLOR_2 = 0xFFFF9800;
20 | private static final int COLOR_3 = 0xFFFF5722;
21 | private static final int COLOR_4 = 0xFFF44336;
22 |
23 | private final Paint[] circlePaints = new Paint[4];
24 |
25 | private int centerX;
26 | private int centerY;
27 |
28 | private float maxOuterDotsRadius;
29 | private float maxInnerDotsRadius;
30 | private float maxDotSize;
31 |
32 | private float currentProgress = 0;
33 |
34 | private float currentRadius1 = 0;
35 | private float currentDotSize1 = 0;
36 |
37 | private float currentDotSize2 = 0;
38 | private float currentRadius2 = 0;
39 |
40 | private ArgbEvaluator argbEvaluator = new ArgbEvaluator();
41 |
42 | public DotsView(Context context) {
43 | super(context);
44 | init();
45 | }
46 |
47 | public DotsView(Context context, AttributeSet attrs) {
48 | super(context, attrs);
49 | init();
50 | }
51 |
52 | public DotsView(Context context, AttributeSet attrs, int defStyleAttr) {
53 | super(context, attrs, defStyleAttr);
54 | init();
55 | }
56 |
57 | public DotsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
58 | super(context, attrs, defStyleAttr, defStyleRes);
59 | init();
60 | }
61 |
62 | private void init() {
63 | for (int i = 0; i < circlePaints.length; i++) {
64 | circlePaints[i] = new Paint();
65 | circlePaints[i].setStyle(Paint.Style.FILL);
66 | }
67 | }
68 |
69 | @Override
70 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
71 | super.onSizeChanged(w, h, oldw, oldh);
72 | centerX = w / 2;
73 | centerY = h / 2;
74 | maxDotSize = 20;
75 | maxOuterDotsRadius = w / 2 - maxDotSize * 2;
76 | maxInnerDotsRadius = 0.8f * maxOuterDotsRadius;
77 | }
78 |
79 | @Override
80 | protected void onDraw(Canvas canvas) {
81 | drawOuterDotsFrame(canvas);
82 | drawInnerDotsFrame(canvas);
83 | }
84 |
85 | private void drawOuterDotsFrame(Canvas canvas) {
86 | for (int i = 0; i < DOTS_COUNT; i++) {
87 | int cX = (int) (centerX + currentRadius1 * Math.cos(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
88 | int cY = (int) (centerY + currentRadius1 * Math.sin(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
89 | canvas.drawCircle(cX, cY, currentDotSize1, circlePaints[i % circlePaints.length]);
90 | }
91 | }
92 |
93 | private void drawInnerDotsFrame(Canvas canvas) {
94 | for (int i = 0; i < DOTS_COUNT; i++) {
95 | int cX = (int) (centerX + currentRadius2 * Math.cos((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
96 | int cY = (int) (centerY + currentRadius2 * Math.sin((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
97 | canvas.drawCircle(cX, cY, currentDotSize2, circlePaints[(i + 1) % circlePaints.length]);
98 | }
99 | }
100 |
101 | public void setCurrentProgress(float currentProgress) {
102 | this.currentProgress = currentProgress;
103 |
104 | updateInnerDotsPosition();
105 | updateOuterDotsPosition();
106 | updateDotsPaints();
107 | updateDotsAlpha();
108 |
109 | postInvalidate();
110 | }
111 |
112 | public float getCurrentProgress() {
113 | return currentProgress;
114 | }
115 |
116 | private void updateInnerDotsPosition() {
117 | if (currentProgress < 0.3f) {
118 | this.currentRadius2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0, 0.3f, 0.f, maxInnerDotsRadius);
119 | } else {
120 | this.currentRadius2 = maxInnerDotsRadius;
121 | }
122 |
123 | if (currentProgress < 0.2) {
124 | this.currentDotSize2 = maxDotSize;
125 | } else if (currentProgress < 0.5) {
126 | this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.2f, 0.5f, maxDotSize, 0.3 * maxDotSize);
127 | } else {
128 | this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, maxDotSize * 0.3f, 0);
129 | }
130 |
131 | }
132 |
133 | private void updateOuterDotsPosition() {
134 | if (currentProgress < 0.3f) {
135 | this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.0f, 0.3f, 0, maxOuterDotsRadius * 0.8f);
136 | } else {
137 | this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.3f, 1f, 0.8f * maxOuterDotsRadius, maxOuterDotsRadius);
138 | }
139 |
140 | if (currentProgress < 0.7) {
141 | this.currentDotSize1 = maxDotSize;
142 | } else {
143 | this.currentDotSize1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.7f, 1f, maxDotSize, 0);
144 | }
145 | }
146 |
147 | private void updateDotsPaints() {
148 | if (currentProgress < 0.5f) {
149 | float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0f, 0.5f, 0, 1f);
150 | circlePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
151 | circlePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
152 | circlePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
153 | circlePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
154 | } else {
155 | float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, 0, 1f);
156 | circlePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
157 | circlePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
158 | circlePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
159 | circlePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
160 | }
161 | }
162 |
163 | private void updateDotsAlpha() {
164 | float progress = (float) Utils.clamp(currentProgress, 0.6f, 1f);
165 | int alpha = (int) Utils.mapValueFromRangeToRange(progress, 0.6f, 1f, 255, 0);
166 | circlePaints[0].setAlpha(alpha);
167 | circlePaints[1].setAlpha(alpha);
168 | circlePaints[2].setAlpha(alpha);
169 | circlePaints[3].setAlpha(alpha);
170 | }
171 |
172 | public static final Property DOTS_PROGRESS = new Property(Float.class, "dotsProgress") {
173 | @Override
174 | public Float get(DotsView object) {
175 | return object.getCurrentProgress();
176 | }
177 |
178 | @Override
179 | public void set(DotsView object, Float value) {
180 | object.setCurrentProgress(value);
181 | }
182 | };
183 | }
184 |
--------------------------------------------------------------------------------
/app/src/main/java/frogermcs/io/likeanimation/LikeButtonView.java:
--------------------------------------------------------------------------------
1 | package frogermcs.io.likeanimation;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ObjectAnimator;
7 | import android.annotation.TargetApi;
8 | import android.content.Context;
9 | import android.os.Build;
10 | import android.util.AttributeSet;
11 | import android.view.LayoutInflater;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 | import android.view.animation.AccelerateDecelerateInterpolator;
15 | import android.view.animation.DecelerateInterpolator;
16 | import android.view.animation.OvershootInterpolator;
17 | import android.widget.FrameLayout;
18 | import android.widget.ImageView;
19 |
20 | import butterknife.Bind;
21 | import butterknife.ButterKnife;
22 |
23 | /**
24 | * Created by Miroslaw Stanek on 20.12.2015.
25 | */
26 | public class LikeButtonView extends FrameLayout implements View.OnClickListener {
27 | private static final DecelerateInterpolator DECCELERATE_INTERPOLATOR = new DecelerateInterpolator();
28 | private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator();
29 | private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator(4);
30 |
31 | @Bind(R.id.ivStar)
32 | ImageView ivStar;
33 | @Bind(R.id.vDotsView)
34 | DotsView vDotsView;
35 | @Bind(R.id.vCircle)
36 | CircleView vCircle;
37 |
38 | private boolean isChecked;
39 | private AnimatorSet animatorSet;
40 |
41 | public LikeButtonView(Context context) {
42 | super(context);
43 | init();
44 | }
45 |
46 | public LikeButtonView(Context context, AttributeSet attrs) {
47 | super(context, attrs);
48 | init();
49 | }
50 |
51 | public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
52 | super(context, attrs, defStyleAttr);
53 | init();
54 | }
55 |
56 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
57 | public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
58 | super(context, attrs, defStyleAttr, defStyleRes);
59 | init();
60 | }
61 |
62 | private void init() {
63 | LayoutInflater.from(getContext()).inflate(R.layout.view_like_button, this, true);
64 | ButterKnife.bind(this);
65 | setOnClickListener(this);
66 | }
67 |
68 | @Override
69 | public void onClick(View v) {
70 | isChecked = !isChecked;
71 | ivStar.setImageResource(isChecked ? R.drawable.ic_star_rate_on : R.drawable.ic_star_rate_off);
72 |
73 | if (animatorSet != null) {
74 | animatorSet.cancel();
75 | }
76 |
77 | if (isChecked) {
78 | ivStar.animate().cancel();
79 | ivStar.setScaleX(0);
80 | ivStar.setScaleY(0);
81 | vCircle.setInnerCircleRadiusProgress(0);
82 | vCircle.setOuterCircleRadiusProgress(0);
83 | vDotsView.setCurrentProgress(0);
84 |
85 | animatorSet = new AnimatorSet();
86 |
87 | ObjectAnimator outerCircleAnimator = ObjectAnimator.ofFloat(vCircle, CircleView.OUTER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
88 | outerCircleAnimator.setDuration(250);
89 | outerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);
90 |
91 | ObjectAnimator innerCircleAnimator = ObjectAnimator.ofFloat(vCircle, CircleView.INNER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
92 | innerCircleAnimator.setDuration(200);
93 | innerCircleAnimator.setStartDelay(200);
94 | innerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);
95 |
96 | ObjectAnimator starScaleYAnimator = ObjectAnimator.ofFloat(ivStar, ImageView.SCALE_Y, 0.2f, 1f);
97 | starScaleYAnimator.setDuration(350);
98 | starScaleYAnimator.setStartDelay(250);
99 | starScaleYAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);
100 |
101 | ObjectAnimator starScaleXAnimator = ObjectAnimator.ofFloat(ivStar, ImageView.SCALE_X, 0.2f, 1f);
102 | starScaleXAnimator.setDuration(350);
103 | starScaleXAnimator.setStartDelay(250);
104 | starScaleXAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);
105 |
106 | ObjectAnimator dotsAnimator = ObjectAnimator.ofFloat(vDotsView, DotsView.DOTS_PROGRESS, 0, 1f);
107 | dotsAnimator.setDuration(900);
108 | dotsAnimator.setStartDelay(50);
109 | dotsAnimator.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR);
110 |
111 | animatorSet.playTogether(
112 | outerCircleAnimator,
113 | innerCircleAnimator,
114 | starScaleYAnimator,
115 | starScaleXAnimator,
116 | dotsAnimator
117 | );
118 |
119 | animatorSet.addListener(new AnimatorListenerAdapter() {
120 | @Override
121 | public void onAnimationCancel(Animator animation) {
122 | vCircle.setInnerCircleRadiusProgress(0);
123 | vCircle.setOuterCircleRadiusProgress(0);
124 | vDotsView.setCurrentProgress(0);
125 | ivStar.setScaleX(1);
126 | ivStar.setScaleY(1);
127 | }
128 | });
129 |
130 | animatorSet.start();
131 | }
132 | }
133 |
134 | @Override
135 | public boolean onTouchEvent(MotionEvent event) {
136 | switch (event.getAction()) {
137 | case MotionEvent.ACTION_DOWN:
138 | ivStar.animate().scaleX(0.7f).scaleY(0.7f).setDuration(150).setInterpolator(DECCELERATE_INTERPOLATOR);
139 | setPressed(true);
140 | break;
141 |
142 | case MotionEvent.ACTION_MOVE:
143 | float x = event.getX();
144 | float y = event.getY();
145 | boolean isInside = (x > 0 && x < getWidth() && y > 0 && y < getHeight());
146 | if (isPressed() != isInside) {
147 | setPressed(isInside);
148 | }
149 | break;
150 |
151 | case MotionEvent.ACTION_UP:
152 | ivStar.animate().scaleX(1).scaleY(1).setInterpolator(DECCELERATE_INTERPOLATOR);
153 | if (isPressed()) {
154 | performClick();
155 | setPressed(false);
156 | }
157 | break;
158 | }
159 | return true;
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/app/src/main/java/frogermcs/io/likeanimation/MainActivity.java:
--------------------------------------------------------------------------------
1 | package frogermcs.io.likeanimation;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | public class MainActivity extends AppCompatActivity {
7 |
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | setContentView(R.layout.activity_main);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/frogermcs/io/likeanimation/Utils.java:
--------------------------------------------------------------------------------
1 | package frogermcs.io.likeanimation;
2 |
3 | /**
4 | * Created by Miroslaw Stanek on 21.12.2015.
5 | */
6 | public class Utils {
7 | public static double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) {
8 | return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow));
9 | }
10 |
11 | public static double clamp(double value, double low, double high) {
12 | return Math.min(Math.max(value, low), high);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apuroth/LikeAnimation/078b3409d9040ac4da58461d5cf743bf91a8bc6f/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_star_rate_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apuroth/LikeAnimation/078b3409d9040ac4da58461d5cf743bf91a8bc6f/app/src/main/res/drawable-xxhdpi/ic_star_rate_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_star_rate_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apuroth/LikeAnimation/078b3409d9040ac4da58461d5cf743bf91a8bc6f/app/src/main/res/drawable-xxhdpi/ic_star_rate_on.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_like_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
18 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | LikeAnimation
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/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.1.0-alpha1'
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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apuroth/LikeAnimation/078b3409d9040ac4da58461d5cf743bf91a8bc6f/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.10-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 |
--------------------------------------------------------------------------------