Java tutorial
/* * Copyright 2016 Google Inc. All Rights Reserved. * * 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 com.google.samples.apps.ourstreets.view; import android.animation.Animator; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Point; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.ColorRes; import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.support.v4.hardware.display.DisplayManagerCompat; import android.text.Html; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.util.Patterns; import android.util.Property; import android.view.Surface; import android.view.View; import android.view.ViewAnimationUtils; import android.view.WindowInsets; import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.TextView; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.BitmapDescriptor; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.Marker; /** * Utilities for view manipulation. */ public class ViewUtils { public static final Property<FrameLayout, Integer> FOREGROUND_COLOR = new Property<FrameLayout, Integer>( Integer.class, "foregroundColor") { @Override public void set(FrameLayout layout, Integer value) { if (layout.getForeground() instanceof ColorDrawable) { ((ColorDrawable) layout.getForeground().mutate()).setColor(value); } else { layout.setForeground(new ColorDrawable(value)); } } @Override public Integer get(FrameLayout layout) { if (layout.getForeground() instanceof ColorDrawable) { return ((ColorDrawable) layout.getForeground()).getColor(); } else { return Color.TRANSPARENT; } } }; /** * Set the status bar color of an activity to a specified value. * * @param activity The activity to set the colorResId for. * @param colorResId The value to use. */ public static void setStatusBarColor(@NonNull Activity activity, @ColorRes int colorResId) { //noinspection ConstantConditions if (activity == null) { return; } final int backgroundColor = ContextCompat.getColor(activity, colorResId); activity.getWindow().setStatusBarColor(backgroundColor); } /** * Sets a text on a {@link TextView}, provided via viewResId, within a parent view. * If there's a web url in the tag the text will be converted from Html, respecting tags. * * @param parent The view's parent. * @param viewResId The resource to resolve. * @param text The text to set. */ public static void setTextOn(@NonNull View parent, @IdRes int viewResId, @Nullable CharSequence text) { if (TextUtils.isEmpty(text)) { text = ""; } View view = parent.findViewById(viewResId); if (view instanceof TextView) { TextView textView = (TextView) view; // Only perform Html conversion if there's actually an Url in the text. if (Patterns.WEB_URL.matcher(text).find()) { textView.setText(Html.fromHtml(text.toString())); textView.setMovementMethod(LinkMovementMethod.getInstance()); } else { textView.setText(text); } } } /** * Create a simple circular reveal for a given view id within a root view. * This reveal will start from the start view's boundaries until it fills the root layout. * * @param rootView The layout's root. * @param startViewId The id of the view to use as animation source. * @param interpolator The interpolator to use. * @return The created circular reveal. */ @NonNull public static Animator createCircularReveal(@NonNull View rootView, @IdRes int startViewId, @NonNull Interpolator interpolator) { final View startView = rootView.findViewById(startViewId); return createCircularReveal(startView, rootView, interpolator); } /** * Create a simple circular reveal from a given start view to it's target view. * This reveal will start from the start view's boundaries until it fills the target view. * * @param startView The view to start the reveal from. * @param targetView The target view which will be displayed once the reveal is done. * @param interpolator The interpolator to use. * @return The created circular reveal. */ @NonNull public static Animator createCircularReveal(@NonNull View startView, @NonNull View targetView, @NonNull Interpolator interpolator) { Point center = getCenterForView(startView); return createCircularReveal(center, startView.getWidth(), targetView, interpolator); } /** * Create a simple circular reveal from a given start view to it's target view. * This reveal will start from the start view's boundaries until it fills the target view. * * @param center The center x and y coordinates of the start circle. * @param width The initial width of the view's coordinates. * @param targetView The target view which will be displayed once the reveal is done. * @param interpolator The interpolator to use. * @return The created circular reveal. */ @NonNull public static Animator createCircularReveal(@NonNull Point center, int width, @NonNull View targetView, @NonNull Interpolator interpolator) { final Animator circularReveal = ViewAnimationUtils.createCircularReveal(targetView, center.x, center.y, width, (float) Math.hypot(center.x, center.y)); circularReveal.setInterpolator(interpolator); return circularReveal; } /** * Basically a reverse {@link #createCircularReveal(Point, int, View, Interpolator)}. * * @param center The center x and y coordinates of the final circle. * @param width The final width of the view's coordinates. * @param startView The view which will initially displayed. * @param interpolator The interpolator to use. * @return The created circular conceal. */ public static Animator createCircularConceal(@NonNull Point center, int width, @NonNull View startView, @NonNull Interpolator interpolator) { final Animator circularReveal = ViewAnimationUtils.createCircularReveal(startView, center.x, center.y, (float) Math.hypot(center.x, center.y), width); circularReveal.setInterpolator(interpolator); return circularReveal; } /** * Create a color change animation over a foreground property of a {@link FrameLayout}. * * @param target The target view. * @param startColorRes The color to start from. * @param targetColorRes The color this animation will end with. * @param interpolator The interpolator to use. * @return The color change animation. */ @NonNull public static ObjectAnimator createColorChange(@NonNull FrameLayout target, @ColorRes int startColorRes, @ColorRes int targetColorRes, @NonNull Interpolator interpolator) { Context context = target.getContext(); final int startColor = ContextCompat.getColor(context, startColorRes); final int targetColor = ContextCompat.getColor(context, targetColorRes); ObjectAnimator colorChange = ObjectAnimator.ofInt(target, ViewUtils.FOREGROUND_COLOR, startColor, targetColor); colorChange.setEvaluator(new ArgbEvaluator()); colorChange.setInterpolator(interpolator); colorChange.setDuration(context.getResources().getInteger(android.R.integer.config_longAnimTime)); return colorChange; } /** * Get the center of a given view. * * @param view The view to get coordinates from. * @return The center of the given view. */ public static Point getCenterForView(@NonNull View view) { final int centerX = (view.getLeft() + view.getRight()) / 2; final int centerY = (view.getTop() + view.getBottom()) / 2; return new Point(centerX, centerY); } /** * Applies top window insets for a view. * * @param view The view to apply insets for. */ public static void applyTopWindowInsetsForView(@NonNull final View view) { view.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { v.setPadding(v.getPaddingLeft(), insets.getSystemWindowInsetTop() + v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom()); return insets; } }); view.requestApplyInsets(); } /** * Checks whether the main display is in landscape. * * @param context The context to check with. * @return <code>true</code> if the main display is in landscape, else <code>false</code>. */ public static boolean isMainDisplayInLandscape(Context context) { int rotation = DisplayManagerCompat.getInstance(context).getDisplay(0).getRotation(); return rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270; } /** * Creates a {@link BitmapDescriptor} from a drawable. * This is particularly useful for {@link GoogleMap} {@link Marker}s. * * @param drawable The drawable that should be a {@link BitmapDescriptor}. * @return The created {@link BitmapDescriptor}. */ @NonNull public static BitmapDescriptor getBitmapDescriptorFromDrawable(@NonNull Drawable drawable) { BitmapDescriptor bitmapDescriptor; // Usually the pin could be loaded via BitmapDescriptorFactory directly. // The target map_pin is a VectorDrawable which is currently not supported // within BitmapDescriptors. int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); drawable.setBounds(0, 0, width, height); Bitmap markerBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(markerBitmap); drawable.draw(canvas); bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(markerBitmap); return bitmapDescriptor; } }