/* * Copyright 2015 Google Inc. * * 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.plaidapp.util; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Outline; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.os.Build; import android.support.annotation.ColorInt; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.v7.graphics.Palette; import android.text.TextPaint; import android.util.DisplayMetrics; import android.util.Property; import android.util.TypedValue; import android.view.View; import android.view.ViewOutlineProvider; import android.widget.ImageView; import android.widget.TextView; /** * Utility methods for working with Views. */ public class ViewUtils { private ViewUtils() { } public static int getActionBarSize(@NonNull Context context) { TypedValue value = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.actionBarSize, value, true); int actionBarSize = TypedValue.complexToDimensionPixelSize( value.data, context.getResources().getDisplayMetrics()); return actionBarSize; } /** * Determine if the navigation bar will be on the bottom of the screen, based on logic in * PhoneWindowManager. */ public static boolean isNavBarOnBottom(@NonNull Context context) { final Resources res= context.getResources(); final Configuration cfg = context.getResources().getConfiguration(); final DisplayMetrics dm =res.getDisplayMetrics(); boolean canMove = (dm.widthPixels != dm.heightPixels && cfg.smallestScreenWidthDp < 600); return(!canMove || dm.widthPixels < dm.heightPixels); } public static RippleDrawable createRipple(@ColorInt int color, @FloatRange(from = 0f, to = 1f) float alpha, boolean bounded) { color = ColorUtils.modifyAlpha(color, alpha); return new RippleDrawable(ColorStateList.valueOf(color), null, bounded ? new ColorDrawable(Color.WHITE) : null); } public static RippleDrawable createRipple(@NonNull Palette palette, @FloatRange(from = 0f, to = 1f) float darkAlpha, @FloatRange(from = 0f, to = 1f) float lightAlpha, @ColorInt int fallbackColor, boolean bounded) { int rippleColor = fallbackColor; if (palette != null) { // try the named swatches in preference order if (palette.getVibrantSwatch() != null) { rippleColor = ColorUtils.modifyAlpha(palette.getVibrantSwatch().getRgb(), darkAlpha); } else if (palette.getLightVibrantSwatch() != null) { rippleColor = ColorUtils.modifyAlpha(palette.getLightVibrantSwatch().getRgb(), lightAlpha); } else if (palette.getDarkVibrantSwatch() != null) { rippleColor = ColorUtils.modifyAlpha(palette.getDarkVibrantSwatch().getRgb(), darkAlpha); } else if (palette.getMutedSwatch() != null) { rippleColor = ColorUtils.modifyAlpha(palette.getMutedSwatch().getRgb(), darkAlpha); } else if (palette.getLightMutedSwatch() != null) { rippleColor = ColorUtils.modifyAlpha(palette.getLightMutedSwatch().getRgb(), lightAlpha); } else if (palette.getDarkMutedSwatch() != null) { rippleColor = ColorUtils.modifyAlpha(palette.getDarkMutedSwatch().getRgb(), darkAlpha); } } return new RippleDrawable(ColorStateList.valueOf(rippleColor), null, bounded ? new ColorDrawable(Color.WHITE) : null); } public static void setLightStatusBar(@NonNull View view) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int flags = view.getSystemUiVisibility(); flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; view.setSystemUiVisibility(flags); } } public static void clearLightStatusBar(@NonNull View view) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int flags = view.getSystemUiVisibility(); flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; view.setSystemUiVisibility(flags); } } /** * Recursive binary search to find the best size for the text. * * Adapted from https://github.com/grantland/android-autofittextview */ public static float getSingleLineTextSize(String text, TextPaint paint, float targetWidth, float low, float high, float precision, DisplayMetrics metrics) { final float mid = (low + high) / 2.0f; paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, mid, metrics)); final float maxLineWidth = paint.measureText(text); if ((high - low) < precision) { return low; } else if (maxLineWidth > targetWidth) { return getSingleLineTextSize(text, paint, targetWidth, low, mid, precision, metrics); } else if (maxLineWidth < targetWidth) { return getSingleLineTextSize(text, paint, targetWidth, mid, high, precision, metrics); } else { return mid; } } public static final Property<View, Integer> BACKGROUND_COLOR = AnimUtils.createIntProperty(new AnimUtils.IntProp<View>("backgroundColor") { @Override public void set(View view, int color) { view.setBackgroundColor(color); } @Override public int get(View view) { Drawable d = view.getBackground(); if (d instanceof ColorDrawable) { return ((ColorDrawable) d).getColor(); } return Color.TRANSPARENT; } }); public static final Property<TextView, Integer> TEXT_COLOR = AnimUtils.createIntProperty(new AnimUtils.IntProp<TextView>("textColor") { @Override public void set(TextView textView, int textColor) { textView.setTextColor(textColor); } @Override public int get(TextView textView) { return textView.getCurrentTextColor(); } }); public static final Property<Drawable, Integer> DRAWABLE_ALPHA = AnimUtils.createIntProperty(new AnimUtils.IntProp<Drawable>("alpha") { @Override public void set(Drawable drawable, int alpha) { drawable.setAlpha(alpha); } @Override public int get(Drawable drawable) { return drawable.getAlpha(); } }); public static final Property<ImageView, Integer> IMAGE_ALPHA = AnimUtils.createIntProperty(new AnimUtils.IntProp<ImageView>("imageAlpha") { @Override public void set(ImageView imageView, int alpha) { imageView.setImageAlpha(alpha); } @Override public int get(ImageView imageView) { return imageView.getImageAlpha(); } }); public static final ViewOutlineProvider CIRCULAR_OUTLINE = new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { outline.setOval(view.getPaddingLeft(), view.getPaddingTop(), view.getWidth() - view.getPaddingRight(), view.getHeight() - view.getPaddingBottom()); } }; /** * Determines if two views intersect in the window. */ public static boolean viewsIntersect(View view1, View view2) { if (view1 == null || view2 == null) return false; final int[] view1Loc = new int[2]; view1.getLocationOnScreen(view1Loc); final Rect view1Rect = new Rect(view1Loc[0], view1Loc[1], view1Loc[0] + view1.getWidth(), view1Loc[1] + view1.getHeight()); int[] view2Loc = new int[2]; view2.getLocationOnScreen(view2Loc); final Rect view2Rect = new Rect(view2Loc[0], view2Loc[1], view2Loc[0] + view2.getWidth(), view2Loc[1] + view2.getHeight()); return view1Rect.intersect(view2Rect); } public static void setPaddingStart(View view, int paddingStart) { view.setPaddingRelative(paddingStart, view.getPaddingTop(), view.getPaddingEnd(), view.getPaddingBottom()); } public static void setPaddingTop(View view, int paddingTop) { view.setPaddingRelative(view.getPaddingStart(), paddingTop, view.getPaddingEnd(), view.getPaddingBottom()); } public static void setPaddingEnd(View view, int paddingEnd) { view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), paddingEnd, view.getPaddingBottom()); } public static void setPaddingBottom(View view, int paddingBottom) { view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), view.getPaddingEnd(), paddingBottom); } }