blob: 2ade6cf054460c33380fc80c932ec9b50b1f809e [file] [log] [blame]
yueg0b4755c2017-12-18 10:01:03 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.newbubble;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator;
22import android.graphics.Outline;
23import android.graphics.Rect;
24import android.view.View;
25import android.view.ViewOutlineProvider;
26
27/**
28 * A {@link ViewOutlineProvider} that provides an outline that interpolates between two radii and
29 * two {@link Rect}s.
30 *
31 * <p>An example usage of this provider is an outline that starts out as a circle and ends as a
32 * rounded rectangle.
33 */
34public class RoundedRectRevealOutlineProvider extends ViewOutlineProvider {
linyuh183cb712017-12-27 17:02:37 -080035 private final float startRadius;
36 private final float endRadius;
yueg0b4755c2017-12-18 10:01:03 -080037
linyuh183cb712017-12-27 17:02:37 -080038 private final Rect startRect;
39 private final Rect endRect;
yueg0b4755c2017-12-18 10:01:03 -080040
linyuh183cb712017-12-27 17:02:37 -080041 private final Rect outline;
42 private float outlineRadius;
yueg0b4755c2017-12-18 10:01:03 -080043
44 public RoundedRectRevealOutlineProvider(
45 float startRadius, float endRadius, Rect startRect, Rect endRect) {
linyuh183cb712017-12-27 17:02:37 -080046 this.startRadius = startRadius;
47 this.endRadius = endRadius;
48 this.startRect = startRect;
49 this.endRect = endRect;
yueg0b4755c2017-12-18 10:01:03 -080050
linyuh183cb712017-12-27 17:02:37 -080051 outline = new Rect();
yueg0b4755c2017-12-18 10:01:03 -080052 }
53
54 @Override
55 public void getOutline(View v, Outline outline) {
linyuh183cb712017-12-27 17:02:37 -080056 outline.setRoundRect(this.outline, outlineRadius);
yueg0b4755c2017-12-18 10:01:03 -080057 }
58
59 /** Sets the progress, from 0 to 1, of the reveal animation. */
60 public void setProgress(float progress) {
linyuh183cb712017-12-27 17:02:37 -080061 outlineRadius = (1 - progress) * startRadius + progress * endRadius;
yueg0b4755c2017-12-18 10:01:03 -080062
linyuh183cb712017-12-27 17:02:37 -080063 outline.left = (int) ((1 - progress) * startRect.left + progress * endRect.left);
64 outline.top = (int) ((1 - progress) * startRect.top + progress * endRect.top);
65 outline.right = (int) ((1 - progress) * startRect.right + progress * endRect.right);
66 outline.bottom = (int) ((1 - progress) * startRect.bottom + progress * endRect.bottom);
yueg0b4755c2017-12-18 10:01:03 -080067 }
68
69 ValueAnimator createRevealAnimator(final View revealView, boolean isReversed) {
70 ValueAnimator valueAnimator =
71 isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f);
72
73 valueAnimator.addListener(
74 new AnimatorListenerAdapter() {
linyuh183cb712017-12-27 17:02:37 -080075 private boolean wasCanceled = false;
yueg0b4755c2017-12-18 10:01:03 -080076
77 @Override
78 public void onAnimationStart(Animator animation) {
79 revealView.setOutlineProvider(RoundedRectRevealOutlineProvider.this);
80 revealView.setClipToOutline(true);
81 }
82
83 @Override
84 public void onAnimationCancel(Animator animation) {
linyuh183cb712017-12-27 17:02:37 -080085 wasCanceled = true;
yueg0b4755c2017-12-18 10:01:03 -080086 }
87
88 @Override
89 public void onAnimationEnd(Animator animation) {
linyuh183cb712017-12-27 17:02:37 -080090 if (!wasCanceled) {
yueg0b4755c2017-12-18 10:01:03 -080091 revealView.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
92 revealView.setClipToOutline(false);
93 }
94 }
95 });
96
97 valueAnimator.addUpdateListener(
98 (currentValueAnimator) -> {
99 float progress = (Float) currentValueAnimator.getAnimatedValue();
100 setProgress(progress);
101 revealView.invalidateOutline();
102 });
103 return valueAnimator;
104 }
105}