1 /*
2  * Copyright 2019 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 
17 package com.android.car.apps.common.util;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.annotation.NonNull;
22 import android.content.res.Resources;
23 import android.content.res.TypedArray;
24 import android.view.View;
25 import android.widget.TextView;
26 
27 import androidx.annotation.Nullable;
28 import androidx.annotation.StringRes;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * Utility methods to operate over views.
35  */
36 public class ViewUtils {
37     /**
38      * Hides a view using a fade-out animation
39      *
40      * @param view     {@link View} to be hidden
41      * @param duration animation duration in milliseconds.
42      */
hideViewAnimated(@onNull View view, int duration)43     public static void hideViewAnimated(@NonNull View view, int duration) {
44         // Cancel existing animation to avoid race condition
45         // if show and hide are called at the same time
46         view.animate().cancel();
47 
48         if (!view.isLaidOut()) {
49             // If the view hasn't been displayed yet, just adjust visibility without animation
50             view.setVisibility(View.GONE);
51             return;
52         }
53 
54         view.animate()
55                 .setDuration(duration)
56                 .setListener(hideViewAfterAnimation(view))
57                 .alpha(0f);
58     }
59 
60     /** Returns an AnimatorListener that hides the view at the end. */
hideViewAfterAnimation(View view)61     public static Animator.AnimatorListener hideViewAfterAnimation(View view) {
62         return new AnimatorListenerAdapter() {
63             @Override
64             public void onAnimationEnd(Animator animation) {
65                 view.setVisibility(View.GONE);
66             }
67         };
68     }
69 
70     /**
71      * Hides views using a fade-out animation
72      *
73      * @param views    {@link View}s to be hidden
74      * @param duration animation duration in milliseconds.
75      */
76     public static void hideViewsAnimated(@Nullable List<View> views, int duration) {
77         for (View view : views) {
78             if (view != null) {
79                 hideViewAnimated(view, duration);
80             }
81         }
82     }
83 
84     /**
85      * Shows a view using a fade-in animation
86      *
87      * @param view     {@link View} to be shown
88      * @param duration animation duration in milliseconds.
89      */
90     public static void showViewAnimated(@NonNull View view, int duration) {
91         // Cancel existing animation to avoid race condition
92         // if show and hide are called at the same time
93         view.animate().cancel();
94 
95         // Do the animation even if the view isn't laid out which is often the case for a view
96         // that isn't shown (otherwise the view just pops onto the screen...
97 
98         view.animate()
99                 .setDuration(duration)
100                 .setListener(new AnimatorListenerAdapter() {
101                     @Override
102                     public void onAnimationStart(Animator animation) {
103                         view.setVisibility(View.VISIBLE);
104                     }
105                 })
106                 .alpha(1f);
107     }
108 
109     /**
110      * Shows views using a fade-out animation
111      *
112      * @param views    {@link View}s to be shown.
113      * @param duration animation duration in milliseconds.
114      */
115     public static void showViewsAnimated(@Nullable List<View> views, int duration) {
116         for (View view : views) {
117             if (view != null) {
118                 showViewAnimated(view, duration);
119             }
120         }
121     }
122 
123     /** Sets the visibility of the (optional) view to {@link View#VISIBLE} or {@link View#GONE}. */
124     public static void setVisible(@Nullable View view, boolean visible) {
125         if (view != null) {
126             view.setVisibility(visible ? View.VISIBLE : View.GONE);
127         }
128     }
129 
130     /** Sets the visibility of the views to {@link View#VISIBLE} or {@link View#GONE}. */
131     public static void setVisible(@Nullable List<View> views, boolean visible) {
132         for (View view : views) {
133             setVisible(view, visible);
134         }
135     }
136 
137     /**
138      * Sets the visibility of the (optional) view to {@link View#INVISIBLE} or {@link View#VISIBLE}.
139      */
140     public static void setInvisible(@Nullable View view, boolean invisible) {
141         if (view != null) {
142             view.setVisibility(invisible ? View.INVISIBLE : View.VISIBLE);
143         }
144     }
145 
146     /** Sets the text to the (optional) {@link TextView}. */
147     public static void setText(@Nullable TextView view, @StringRes int resId) {
148         if (view != null) {
149             view.setText(resId);
150         }
151     }
152 
153     /** Sets the text to the (optional) {@link TextView}. */
154     public static void setText(@Nullable TextView view, CharSequence text) {
155         if (view != null) {
156             view.setText(text);
157         }
158     }
159 
160     /** Sets the enabled state of the (optional) view. */
161     public static void setEnabled(@Nullable View view, boolean enabled) {
162         if (view != null) {
163             view.setEnabled(enabled);
164         }
165     }
166 
167     /** Sets the activated state of the (optional) view. */
168     public static void setActivated(@Nullable View view, boolean activated) {
169         if (view != null) {
170             view.setActivated(activated);
171         }
172     }
173 
174     /** Sets onClickListener for the (optional) view. */
175     public static void setOnClickListener(@Nullable View view, @Nullable View.OnClickListener l) {
176         if (view != null) {
177             view.setOnClickListener(l);
178         }
179     }
180 
181     /** Helper interface for {@link #getViewsById(View, Resources, int, Filter)} getViewsById}. */
182     public interface Filter {
183         /** Returns whether a view should be added to the returned List. */
184         boolean isValid(View view);
185     }
186 
187     /** Get views from typed array. */
188     public static List<View> getViewsById(@NonNull View root, @NonNull Resources res, int arrayId,
189             @Nullable Filter filter) {
190         TypedArray viewIds = res.obtainTypedArray(arrayId);
191         List<View> views = new ArrayList<>(viewIds.length());
192         for (int i = 0; i < viewIds.length(); i++) {
193             int viewId = viewIds.getResourceId(i, 0);
194             if (viewId != 0) {
195                 View view = root.findViewById(viewId);
196                 if (view != null && (filter == null || filter.isValid(view))) {
197                     views.add(view);
198                 }
199             }
200         }
201         viewIds.recycle();
202         return views;
203     }
204 }
205