Permalink
Browse files

SwitchIconView now extends from ImageView. All ImageView params suppo…

…rted
1 parent 00d2883 commit 22411d9853002b554069109b834e37518a0b37da @zagum committed Jan 9, 2017
View
@@ -3,7 +3,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.0-beta1'
+ classpath 'com.android.tools.build:gradle:2.2.3'
}
}
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
@@ -0,0 +1,40 @@
+package com.github.zagum.switchicon;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class ReflectionUtils {
+ public static boolean setValue(Object object, String fieldName, Object fieldValue) {
+ Class<?> clazz = object.getClass();
+ while (clazz != null) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ field.set(object, fieldValue);
+ return true;
+ } catch (NoSuchFieldException e) {
+ clazz = clazz.getSuperclass();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return false;
+ }
+
+ public static boolean callMethod(Object object, String methodName, Class<?>... params) {
+ Class<?> clazz = object.getClass();
+ while (clazz != null) {
+ try {
+ Method method = clazz.getDeclaredMethod(methodName, params);
+ method.setAccessible(true);
+ method.invoke(object, null);
+ return true;
+ } catch (NoSuchMethodException e) {
+ clazz = clazz.getSuperclass();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return false;
+ }
+}
@@ -19,7 +19,6 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -28,31 +27,24 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Region;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.VectorDrawable;
import android.os.Build;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
import android.support.annotation.FloatRange;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.graphics.drawable.VectorDrawableCompat;
-import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
-import android.view.View;
import android.view.animation.DecelerateInterpolator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-public class SwitchIconView extends View {
+public class SwitchIconView extends AppCompatImageView {
public static final int ENABLED = 0;
public static final int DISABLED = 1;
private static final int DEFAULT_ANIMATION_DURATION = 300;
- private static final int DASH_THICKNESS_DP = 3;
+ private static final float DASH_THICKNESS_PART = 1f / 12f;
private static final float DEFAULT_DISABLED_ALPHA = .5f;
private static final float SIN_45 = (float) Math.sin(Math.toRadians(45));
@@ -67,14 +59,12 @@
private final long animationDuration;
@FloatRange(from = 0f, to = 1f)
private final float disabledStateAlpha;
- private final int dashThickness;
- private final int padding;
private final int dashXStart;
private final int dashYStart;
- private final int dashLengthXProjection;
- private final int dashLengthYProjection;
- private final Path path;
- private Bitmap icon;
+ private final Path clipPath;
+ private int dashThickness;
+ private int dashLengthXProjection;
+ private int dashLengthYProjection;
@State
private int currentState = ENABLED;
@@ -84,8 +74,6 @@
@NonNull
private final Paint dashPaint;
@NonNull
- private final Paint iconPaint;
- @NonNull
private final Point dashStart = new Point();
@NonNull
private final Point dashEnd = new Point();
@@ -104,11 +92,8 @@ public SwitchIconView(@NonNull Context context, @Nullable AttributeSet attrs, in
TypedArray array = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SwitchIconView, 0, 0);
int iconTintColor;
- int iconResId;
try {
- iconResId = array.getResourceId(R.styleable.SwitchIconView_si_image, 0);
- iconTintColor = array.getColor(R.styleable.SwitchIconView_si_tint_color, 0);
- padding = array.getDimensionPixelSize(R.styleable.SwitchIconView_si_padding, 0);
+ iconTintColor = array.getColor(R.styleable.SwitchIconView_si_tint_color, Color.BLACK);
animationDuration = array.getInteger(R.styleable.SwitchIconView_si_animation_duration, DEFAULT_ANIMATION_DURATION);
disabledStateAlpha = array.getFloat(R.styleable.SwitchIconView_si_disabled_alpha, DEFAULT_DISABLED_ALPHA);
} finally {
@@ -120,33 +105,16 @@ public SwitchIconView(@NonNull Context context, @Nullable AttributeSet attrs, in
+ "Must be value from range [0, 1]");
}
- if (iconResId == 0) {
- throw new IllegalArgumentException("You must set correct icon id");
- }
-
- icon = getBitmapFromDrawable(iconResId);
-
- final float density = getResources().getDisplayMetrics().density;
- dashThickness = (int) (DASH_THICKNESS_DP * density);
-
- dashXStart = -icon.getWidth() / 2;
- dashYStart = -icon.getHeight() / 2;
- dashLengthXProjection = icon.getWidth();
- dashLengthYProjection = icon.getHeight();
-
- if (iconTintColor == 0) {
- iconTintColor = getBitmapColor(icon);
- }
+ setColorFilter(new PorterDuffColorFilter(iconTintColor, PorterDuff.Mode.SRC_IN));
- iconPaint = new Paint();
- iconPaint.setColorFilter(new PorterDuffColorFilter(iconTintColor, PorterDuff.Mode.SRC_IN));
+ dashXStart = getPaddingLeft();
+ dashYStart = getPaddingTop();
dashPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dashPaint.setStyle(Paint.Style.STROKE);
dashPaint.setColorFilter(new PorterDuffColorFilter(iconTintColor, PorterDuff.Mode.SRC_IN));
- dashPaint.setStrokeWidth(dashThickness);
- path = new Path();
+ clipPath = new Path();
initDashCoordinates();
}
@@ -223,58 +191,46 @@ public void onAnimationUpdate(ValueAnimator animation) {
private void setFraction(float fraction) {
this.fraction = fraction;
int alpha = (int) ((disabledStateAlpha + (1f - fraction) * (1f - disabledStateAlpha)) * 255);
- iconPaint.setAlpha(alpha);
+ updateImageAlphaWithoutInvalidate(alpha);
dashPaint.setAlpha(alpha);
- updatePath();
+ updateClipPath();
postInvalidateOnAnimationCompat();
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
-
- final int requiredWidth = icon.getWidth() + 2 * padding;
- final int requiredHeight = icon.getHeight() + 2 * padding;
-
- if (widthSpecMode != MeasureSpec.EXACTLY) {
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(requiredWidth, MeasureSpec.EXACTLY);
- }
-
- if (heightSpecMode != MeasureSpec.EXACTLY) {
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(requiredHeight, MeasureSpec.EXACTLY);
- }
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
+ super.onSizeChanged(width, height, oldWidth, oldHeight);
+ dashLengthXProjection = width - getPaddingLeft() - getPaddingRight();
+ dashLengthYProjection = height - getPaddingTop() - getPaddingBottom();
+ dashThickness = (int) (DASH_THICKNESS_PART * (dashLengthXProjection + dashLengthYProjection) / 2f);
+ dashPaint.setStrokeWidth(dashThickness);
+ initDashCoordinates();
+ updateClipPath();
}
@Override
protected void onDraw(Canvas canvas) {
+ drawDash(canvas);
+ canvas.clipPath(clipPath, Region.Op.XOR);
super.onDraw(canvas);
- if (icon != null) {
- canvas.translate(getWidth() / 2, getHeight() / 2);
- drawDash(canvas);
- canvas.clipPath(path, Region.Op.XOR);
- canvas.drawBitmap(icon, -icon.getWidth() / 2, -icon.getHeight() / 2, iconPaint);
- }
}
private void initDashCoordinates() {
float delta1 = 1.5f * SIN_45 * dashThickness;
float delta2 = 0.5f * SIN_45 * dashThickness;
dashStart.x = (int) (dashXStart + delta2);
dashStart.y = dashYStart + (int) (delta1);
- dashEnd.x = (int) (dashLengthXProjection / 2 - delta1);
- dashEnd.y = (int) (dashLengthYProjection / 2 - delta2);
+ dashEnd.x = (int) (dashXStart + dashLengthXProjection - delta1);
+ dashEnd.y = (int) (dashYStart + dashLengthYProjection - delta2);
}
- private void updatePath() {
+ private void updateClipPath() {
float delta = dashThickness / SIN_45;
- path.reset();
- path.moveTo(dashXStart, dashYStart + delta);
- path.lineTo(dashXStart + delta, dashYStart);
- path.lineTo(dashXStart + dashLengthXProjection * fraction, dashYStart + dashLengthYProjection * fraction - delta);
- path.lineTo(dashXStart + dashLengthXProjection * fraction - delta, dashYStart + dashLengthYProjection * fraction);
+ clipPath.reset();
+ clipPath.moveTo(dashXStart, dashYStart + delta);
+ clipPath.lineTo(dashXStart + delta, dashYStart);
+ clipPath.lineTo(dashXStart + dashLengthXProjection * fraction, dashYStart + dashLengthYProjection * fraction - delta);
+ clipPath.lineTo(dashXStart + dashLengthXProjection * fraction - delta, dashYStart + dashLengthYProjection * fraction);
}
private void drawDash(Canvas canvas) {
@@ -283,40 +239,6 @@ private void drawDash(Canvas canvas) {
canvas.drawLine(dashStart.x, dashStart.y, x, y, dashPaint);
}
- @ColorInt
- private int getBitmapColor(final Bitmap bitmap) {
- int maxAlpha = 0;
- int color = Color.TRANSPARENT;
- for (int y = 0; y < bitmap.getHeight(); y++) {
- for (int x = 0; x < bitmap.getWidth(); x++) {
- final int pixel = bitmap.getPixel(x, y);
- if (pixel != Color.TRANSPARENT) {
- final int alpha = Color.alpha(pixel);
- if (alpha > maxAlpha) {
- maxAlpha = alpha;
- color = pixel;
- }
- }
- }
- }
- return color;
- }
-
- private Bitmap getBitmapFromDrawable(@DrawableRes int drawableId) {
- Drawable drawable = ContextCompat.getDrawable(getContext(), drawableId);
- if (drawable instanceof BitmapDrawable) {
- return ((BitmapDrawable) drawable).getBitmap();
- } else if (drawable instanceof VectorDrawable || drawable instanceof VectorDrawableCompat) {
- Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
- return bitmap;
- } else {
- throw new IllegalArgumentException("unsupported drawable type");
- }
- }
-
private void postInvalidateOnAnimationCompat() {
final long fakeFrameTime = 10;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
@@ -326,9 +248,11 @@ private void postInvalidateOnAnimationCompat() {
}
}
- private void resizeIcon(int newWidth, int newHeight) {
- if (newWidth < 0 || newHeight < 0) return;
- float scale = Math.min((float) newWidth / (float) icon.getWidth(), (float) newHeight / (float) icon.getHeight());
- icon = Bitmap.createScaledBitmap(icon, (int) (icon.getWidth() * scale), (int) (icon.getHeight() * scale), false);
+ private void updateImageAlphaWithoutInvalidate(int alpha) {
+ alpha &= 0xFF;
+ ReflectionUtils.setValue(this, "mAlpha", alpha);
+ ReflectionUtils.setValue(this, "mColorMod", true);
+ Class<?> noParams[] = {};
+ ReflectionUtils.callMethod(this, "applyColorMod", noParams);
}
}
@@ -15,8 +15,6 @@
-->
<resources>
<declare-styleable name="SwitchIconView">
- <attr name="si_image" format="reference"/>
- <attr name="si_padding" format="dimension"/>
<attr name="si_tint_color" format="color"/>
<attr name="si_animation_duration" format="integer"/>
<attr name="si_disabled_alpha" format="float"/>

0 comments on commit 22411d9

Please sign in to comment.