GuidanceStylist.java revision ebd3d9078dbaebd10a9506ca086435eb63e8a2d2
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.widget; 15 16import android.animation.Animator; 17import android.animation.AnimatorInflater; 18import android.content.Context; 19import android.content.res.TypedArray; 20import android.graphics.drawable.Drawable; 21import android.support.annotation.NonNull; 22import android.support.v17.leanback.R; 23import android.util.TypedValue; 24import android.view.LayoutInflater; 25import android.view.View; 26import android.view.ViewGroup; 27import android.widget.ImageView; 28import android.widget.TextView; 29 30import java.util.List; 31 32/** 33 * GuidanceStylist is used within a {@link android.support.v17.leanback.app.GuidedStepFragment} 34 * to display contextual information for the decision(s) required at that step. 35 * <p> 36 * Many aspects of the base GuidanceStylist can be customized through theming; see the theme 37 * attributes below. Note that these attributes are not set on individual elements in layout 38 * XML, but instead would be set in a custom theme. See 39 * <a href="http://developer.android.com/guide/topics/ui/themes.html">Styles and Themes</a> 40 * for more information. 41 * <p> 42 * If these hooks are insufficient, this class may also be subclassed. Subclasses 43 * may wish to override the {@link #onProvideLayoutId} method to change the layout file used to 44 * display the guidance; more complex layouts may be supported by also providing a subclass of 45 * {@link GuidanceStylist.Guidance} with extra fields. 46 * <p> 47 * Note: If an alternate layout is provided, the following view IDs should be used to refer to base 48 * elements: 49 * <ul> 50 * <li>{@link android.support.v17.leanback.R.id#guidance_title}</li> 51 * <li>{@link android.support.v17.leanback.R.id#guidance_description}</li> 52 * <li>{@link android.support.v17.leanback.R.id#guidance_breadcrumb}</li> 53 * <li>{@link android.support.v17.leanback.R.id#guidance_icon}</li> 54 * </ul><p> 55 * View IDs are allowed to be missing, in which case the corresponding views will be null. 56 * 57 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceEntryAnimation 58 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepEntryAnimation 59 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepExitAnimation 60 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReentryAnimation 61 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReturnAnimation 62 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceContainerStyle 63 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceTitleStyle 64 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceDescriptionStyle 65 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceBreadcrumbStyle 66 * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceIconStyle 67 * @see android.support.v17.leanback.app.GuidedStepFragment 68 * @see GuidanceStylist.Guidance 69 */ 70public class GuidanceStylist implements FragmentAnimationProvider { 71 72 /** 73 * A data class representing contextual information for a {@link 74 * android.support.v17.leanback.app.GuidedStepFragment}. Guidance consists of a short title, 75 * a longer description, a breadcrumb to help with global navigation (often indicating where 76 * the back button will lead), and an optional icon. All this information is intended to 77 * provide users with the appropriate context to make the decision(s) required by the current 78 * step. 79 * <p> 80 * Clients may provide a subclass of this if they wish to remember auxiliary data for use in 81 * a customized GuidanceStylist. 82 */ 83 public static class Guidance { 84 private final String mTitle; 85 private final String mDescription; 86 private final String mBreadcrumb; 87 private final Drawable mIconDrawable; 88 89 /** 90 * Constructs a Guidance object with the specified title, description, breadcrumb, and 91 * icon drawable. 92 * @param title The title for the current guided step. 93 * @param description The description for the current guided step. 94 * @param breadcrumb The breadcrumb for the current guided step. 95 * @param icon The icon drawable representing the current guided step. 96 */ 97 public Guidance(String title, String description, String breadcrumb, Drawable icon) { 98 mBreadcrumb = breadcrumb; 99 mTitle = title; 100 mDescription = description; 101 mIconDrawable = icon; 102 } 103 104 /** 105 * Returns the title specified when this Guidance was constructed. 106 * @return The title for this Guidance. 107 */ 108 public String getTitle() { 109 return mTitle; 110 } 111 112 /** 113 * Returns the description specified when this Guidance was constructed. 114 * @return The description for this Guidance. 115 */ 116 public String getDescription() { 117 return mDescription; 118 } 119 120 /** 121 * Returns the breadcrumb specified when this Guidance was constructed. 122 * @return The breadcrumb for this Guidance. 123 */ 124 public String getBreadcrumb() { 125 return mBreadcrumb; 126 } 127 128 /** 129 * Returns the icon drawable specified when this Guidance was constructed. 130 * @return The icon for this Guidance. 131 */ 132 public Drawable getIconDrawable() { 133 return mIconDrawable; 134 } 135 } 136 137 private TextView mTitleView; 138 private TextView mDescriptionView; 139 private TextView mBreadcrumbView; 140 private ImageView mIconView; 141 142 /** 143 * Creates an appropriately configured view for the given Guidance, using the provided 144 * inflater and container. 145 * <p> 146 * <i>Note: Does not actually add the created view to the container; the caller should do 147 * this.</i> 148 * @param inflater The layout inflater to be used when constructing the view. 149 * @param container The view group to be passed in the call to 150 * <code>LayoutInflater.inflate</code>. 151 * @param guidance The guidance data for the view. 152 * @return The view to be added to the caller's view hierarchy. 153 */ 154 public View onCreateView(LayoutInflater inflater, ViewGroup container, Guidance guidance) { 155 View guidanceView = inflater.inflate(onProvideLayoutId(), container, false); 156 mTitleView = (TextView) guidanceView.findViewById(R.id.guidance_title); 157 mBreadcrumbView = (TextView) guidanceView.findViewById(R.id.guidance_breadcrumb); 158 mDescriptionView = (TextView) guidanceView.findViewById(R.id.guidance_description); 159 mIconView = (ImageView) guidanceView.findViewById(R.id.guidance_icon); 160 161 // We allow any of the cached subviews to be null, so that subclasses can choose not to 162 // display a particular piece of information. 163 if (mTitleView != null) { 164 mTitleView.setText(guidance.getTitle()); 165 } 166 if (mBreadcrumbView != null) { 167 mBreadcrumbView.setText(guidance.getBreadcrumb()); 168 } 169 if (mDescriptionView != null) { 170 mDescriptionView.setText(guidance.getDescription()); 171 } 172 if (mIconView != null) { 173 mIconView.setImageDrawable(guidance.getIconDrawable()); 174 } 175 return guidanceView; 176 } 177 178 /** 179 * Provides the resource ID of the layout defining the guidance view. Subclasses may override 180 * to provide their own customized layouts. The base implementation returns 181 * {@link android.support.v17.leanback.R.layout#lb_guidance}. If overridden, the substituted 182 * layout should contain matching IDs for any views that should be managed by the base class; 183 * this can be achieved by starting with a copy of the base layout file. 184 * @return The resource ID of the layout to be inflated to define the guidance view. 185 */ 186 public int onProvideLayoutId() { 187 return R.layout.lb_guidance; 188 } 189 190 /** 191 * Returns the view displaying the title of the guidance. 192 * @return The text view object for the title. 193 */ 194 public TextView getTitleView() { 195 return mTitleView; 196 } 197 198 /** 199 * Returns the view displaying the description of the guidance. 200 * @return The text view object for the description. 201 */ 202 public TextView getDescriptionView() { 203 return mDescriptionView; 204 } 205 206 /** 207 * Returns the view displaying the breadcrumb of the guidance. 208 * @return The text view object for the breadcrumb. 209 */ 210 public TextView getBreadcrumbView() { 211 return mBreadcrumbView; 212 } 213 214 /** 215 * Returns the view displaying the icon of the guidance. 216 * @return The image view object for the icon. 217 */ 218 public ImageView getIconView() { 219 return mIconView; 220 } 221 222 /** 223 * {@inheritDoc} 224 */ 225 @Override 226 public void onActivityEnter(@NonNull List<Animator> animators) { 227 addAnimator(animators, mTitleView, R.attr.guidanceEntryAnimation); 228 addAnimator(animators, mBreadcrumbView, R.attr.guidanceEntryAnimation); 229 addAnimator(animators, mDescriptionView, R.attr.guidanceEntryAnimation); 230 addAnimator(animators, mIconView, R.attr.guidanceEntryAnimation); 231 } 232 233 /** 234 * {@inheritDoc} 235 */ 236 @Override 237 public void onActivityExit(@NonNull List<Animator> animators) {} 238 239 /** 240 * {@inheritDoc} 241 */ 242 @Override 243 public void onFragmentEnter(@NonNull List<Animator> animators) { 244 addAnimator(animators, mTitleView, R.attr.guidedStepEntryAnimation); 245 addAnimator(animators, mBreadcrumbView, R.attr.guidedStepEntryAnimation); 246 addAnimator(animators, mDescriptionView, R.attr.guidedStepEntryAnimation); 247 addAnimator(animators, mIconView, R.attr.guidedStepEntryAnimation); 248 } 249 250 /** 251 * {@inheritDoc} 252 */ 253 @Override 254 public void onFragmentExit(@NonNull List<Animator> animators) { 255 addAnimator(animators, mTitleView, R.attr.guidedStepExitAnimation); 256 addAnimator(animators, mBreadcrumbView, R.attr.guidedStepExitAnimation); 257 addAnimator(animators, mDescriptionView, R.attr.guidedStepExitAnimation); 258 addAnimator(animators, mIconView, R.attr.guidedStepExitAnimation); 259 } 260 261 /** 262 * {@inheritDoc} 263 */ 264 @Override 265 public void onFragmentReenter(@NonNull List<Animator> animators) { 266 addAnimator(animators, mTitleView, R.attr.guidedStepReentryAnimation); 267 addAnimator(animators, mBreadcrumbView, R.attr.guidedStepReentryAnimation); 268 addAnimator(animators, mDescriptionView, R.attr.guidedStepReentryAnimation); 269 addAnimator(animators, mIconView, R.attr.guidedStepReentryAnimation); 270 } 271 272 /** 273 * {@inheritDoc} 274 */ 275 @Override 276 public void onFragmentReturn(@NonNull List<Animator> animators) { 277 addAnimator(animators, mTitleView, R.attr.guidedStepReturnAnimation); 278 addAnimator(animators, mBreadcrumbView, R.attr.guidedStepReturnAnimation); 279 addAnimator(animators, mDescriptionView, R.attr.guidedStepReturnAnimation); 280 addAnimator(animators, mIconView, R.attr.guidedStepReturnAnimation); 281 } 282 283 private void addAnimator(List<Animator> animators, View v, int attrId) { 284 if (v != null) { 285 Context ctx = v.getContext(); 286 TypedValue typedValue = new TypedValue(); 287 ctx.getTheme().resolveAttribute(attrId, typedValue, true); 288 Animator animator = AnimatorInflater.loadAnimator(ctx, typedValue.resourceId); 289 animator.setTarget(v); 290 animators.add(animator); 291 } 292 } 293 294} 295