/* * Copyright (C) 2018 Matthew Lee * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.github.mthli.slice; import android.annotation.TargetApi; import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.Shape; import android.os.Build; import android.support.annotation.ColorInt; import android.support.annotation.ColorRes; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.View; @SuppressWarnings("UnusedReturnValue") public final class Slice { private static final String TAG = Slice.class.getName(); private static final boolean SDK_LOLLIPOP = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; private static final boolean SDK_JB_MR1 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1; @SuppressWarnings("WeakerAccess") public static final float DEFAULT_RADIUS_DP = 2.0f; @SuppressWarnings("WeakerAccess") public static final float DEFAULT_ELEVATION_DP = 2.0f; @SuppressWarnings("WeakerAccess") public static final int DEFAULT_RIPPLE_COLOR = 0x40000000; @SuppressWarnings("WeakerAccess") public static final int DEFAULT_BACKGROUND_COLOR = 0xFFFAFAFA; private View view; private Drawable drawable; public Slice(@NonNull View view) { this.view = view; init(); } @SuppressWarnings("NewApi") private void init() { if (SDK_LOLLIPOP) { drawable = new CustomRoundRectDrawable(DEFAULT_BACKGROUND_COLOR, dp2px(DEFAULT_RADIUS_DP)); } else { drawable = new CustomRoundRectDrawableWithShadow(view.getResources(), DEFAULT_BACKGROUND_COLOR, dp2px(DEFAULT_RADIUS_DP), dp2px(DEFAULT_ELEVATION_DP), dp2px(DEFAULT_ELEVATION_DP)); } if (SDK_JB_MR1) { view.setBackground(drawable); } else { view.setBackgroundDrawable(drawable); } setRipple(DEFAULT_RIPPLE_COLOR); setElevation(DEFAULT_ELEVATION_DP); } private float dp2px(@FloatRange(from = 0.0F) float dp) { return view.getResources().getDisplayMetrics().density * dp; } @NonNull private ColorStateList buildColorStateList(@ColorInt int pressed) { return new ColorStateList(new int[][]{ new int[] {android.R.attr.state_pressed}, new int[] {android.R.attr.state_focused}, new int[] {}}, new int[] {pressed, pressed, pressed} ); } @SuppressWarnings("unused") @NonNull public Slice setColorRes(@ColorRes int colorRes) { return setColor(ContextCompat.getColor(view.getContext(), colorRes)); } @SuppressWarnings("unused") @NonNull public Slice setColor(@ColorInt int color) { if (SDK_LOLLIPOP) { ((CustomRoundRectDrawable) drawable).setColor(color); } else { ((CustomRoundRectDrawableWithShadow) drawable).setColor(color); } return this; } @SuppressWarnings({"NewApi", "unused"}) @NonNull public Slice setElevation(@FloatRange(from = 0.0F) float elevationDp) { if (SDK_LOLLIPOP) { view.setElevation(dp2px(elevationDp)); } else { Log.i(TAG, "setElevation() only support range from 0dp to 2dp pre API 21."); ((CustomRoundRectDrawableWithShadow) drawable).setShadowSize(dp2px(elevationDp)); } return this; } @SuppressWarnings("unused") @NonNull public Slice setRadius(@FloatRange(from = 0.0F) float radiusDp) { if (SDK_LOLLIPOP) { ((CustomRoundRectDrawable) drawable).setRadius(dp2px(radiusDp)); } else { ((CustomRoundRectDrawableWithShadow) drawable).setRadius(dp2px(radiusDp)); } return this; } @SuppressWarnings("unused") @NonNull public Slice setRippleRes(@ColorRes int maskRes) { return setRipple(ContextCompat.getColor(view.getContext(), maskRes)); } @SuppressWarnings("WeakerAccess") @TargetApi(Build.VERSION_CODES.LOLLIPOP) public Slice setRipple(@ColorInt final int mask) { if (SDK_LOLLIPOP) { if (mask != 0) { ShapeDrawable shape = new ShapeDrawable(new Shape() { @Override public void draw(Canvas canvas, Paint paint) { paint.setColor(mask); canvas.drawPath(((CustomRoundRectDrawable) drawable).buildConvexPath(), paint); } }); RippleDrawable ripple = new RippleDrawable(buildColorStateList(mask), drawable, shape); view.setBackground(ripple); } else { view.setBackground(drawable); } } else { Log.i(TAG, "setRipple() only work for API 21+"); } return this; } @SuppressWarnings("unused") @NonNull public Slice showLeftTopRect(boolean show) { if (SDK_LOLLIPOP) { ((CustomRoundRectDrawable) drawable).showLeftTopRect(show); } else { ((CustomRoundRectDrawableWithShadow) drawable).showLeftTopRect(show); } return this; } @SuppressWarnings("unused") @NonNull public Slice showRightTopRect(boolean show) { if (SDK_LOLLIPOP) { ((CustomRoundRectDrawable) drawable).showRightTopRect(show); } else { ((CustomRoundRectDrawableWithShadow) drawable).showRightTopRect(show); } return this; } @SuppressWarnings("unused") @NonNull public Slice showRightBottomRect(boolean show) { if (SDK_LOLLIPOP) { ((CustomRoundRectDrawable) drawable).showRightBottomRect(show); } else { ((CustomRoundRectDrawableWithShadow) drawable).showRightBottomRect(show); } return this; } @SuppressWarnings("unused") @NonNull public Slice showLeftBottomRect(boolean show) { if (SDK_LOLLIPOP) { ((CustomRoundRectDrawable) drawable).showLeftBottomRect(show); } else { ((CustomRoundRectDrawableWithShadow) drawable).showLeftBottomRect(show); } return this; } @SuppressWarnings("unused") @NonNull public Slice showLeftEdgeShadow(boolean show) { if (!SDK_LOLLIPOP) { ((CustomRoundRectDrawableWithShadow) drawable).showLeftEdgeShadow(show); } else { Log.i(TAG, "showLeftEdgeShadow() only work for pre API 21."); } return this; } @SuppressWarnings("unused") @NonNull public Slice showTopEdgeShadow(boolean show) { if (!SDK_LOLLIPOP) { ((CustomRoundRectDrawableWithShadow) drawable).showTopEdgeShadow(show); } else { Log.i(TAG, "showTopEdgeShadow() only work for pre API 21."); } return this; } @SuppressWarnings("unused") @NonNull public Slice showRightEdgeShadow(boolean show) { if (!SDK_LOLLIPOP) { ((CustomRoundRectDrawableWithShadow) drawable).showRightEdgeShadow(show); } else { Log.i(TAG, "showRightEdgeShadow() only work for pre API 21."); } return this; } @SuppressWarnings("unused") @NonNull public Slice showBottomEdgeShadow(boolean show) { if (!SDK_LOLLIPOP) { ((CustomRoundRectDrawableWithShadow) drawable).showBottomEdgeShadow(show); } else { Log.i(TAG, "showBottomEdgeShadow() only work for pre API 21."); } return this; } }