FocusHighlightHelper.java revision 76c3b90228d8c4afc6d24c683e9c95f41ae619c9
1/* 2 * Copyright (C) 2014 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.support.v17.leanback.R; 17import android.view.View; 18import android.view.animation.AccelerateDecelerateInterpolator; 19import android.view.animation.Interpolator; 20import android.animation.TimeAnimator; 21import android.content.res.Resources; 22 23/** 24 * Setup the behavior how to highlight when a item gains focus. 25 */ 26public class FocusHighlightHelper { 27 28 static class FocusAnimator implements TimeAnimator.TimeListener { 29 private final View mView; 30 private final int mDuration; 31 private final ShadowOverlayContainer mWrapper; 32 private final float mScaleDiff; 33 private float mFocusLevel = 0f; 34 private float mFocusLevelStart; 35 private float mFocusLevelDelta; 36 private final TimeAnimator mAnimator = new TimeAnimator(); 37 private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); 38 39 void animateFocus(boolean select, boolean immediate) { 40 endAnimation(); 41 final float end = select ? 1 : 0; 42 if (immediate) { 43 setFocusLevel(end); 44 } else if (mFocusLevel != end) { 45 mFocusLevelStart = mFocusLevel; 46 mFocusLevelDelta = end - mFocusLevelStart; 47 mAnimator.start(); 48 } 49 } 50 51 FocusAnimator(View view, float scale, int duration) { 52 mView = view; 53 mDuration = duration; 54 mScaleDiff = scale - 1f; 55 if (view instanceof ShadowOverlayContainer) { 56 mWrapper = (ShadowOverlayContainer) view; 57 } else { 58 mWrapper = null; 59 } 60 mAnimator.setTimeListener(this); 61 } 62 63 void setFocusLevel(float level) { 64 mFocusLevel = level; 65 float scale = 1f + mScaleDiff * level; 66 mView.setScaleX(scale); 67 mView.setScaleY(scale); 68 if (mWrapper != null) { 69 mWrapper.setShadowFocusLevel(level); 70 } 71 } 72 73 float getFocusLevel() { 74 return mFocusLevel; 75 } 76 77 void endAnimation() { 78 mAnimator.end(); 79 } 80 81 @Override 82 public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 83 float fraction; 84 if (totalTime >= mDuration) { 85 fraction = 1; 86 mAnimator.end(); 87 } else { 88 fraction = (float) (totalTime / (double) mDuration); 89 } 90 if (mInterpolator != null) { 91 fraction = mInterpolator.getInterpolation(fraction); 92 } 93 setFocusLevel(mFocusLevelStart + fraction * mFocusLevelDelta); 94 } 95 } 96 97 static class BrowseItemFocusHighlight implements FocusHighlight { 98 private static final int DURATION_MS = 150; 99 100 private static float[] sScaleFactor = new float[4]; 101 102 private int mScaleIndex; 103 104 BrowseItemFocusHighlight(int zoomIndex) { 105 mScaleIndex = (zoomIndex >= 0 && zoomIndex < sScaleFactor.length) ? 106 zoomIndex : ZOOM_FACTOR_MEDIUM; 107 } 108 109 private static void lazyInit(Resources resources) { 110 if (sScaleFactor[ZOOM_FACTOR_NONE] == 0f) { 111 sScaleFactor[ZOOM_FACTOR_NONE] = 1f; 112 sScaleFactor[ZOOM_FACTOR_SMALL] = 113 resources.getFraction(R.fraction.lb_focus_zoom_factor_small, 1, 1); 114 sScaleFactor[ZOOM_FACTOR_MEDIUM] = 115 resources.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1); 116 sScaleFactor[ZOOM_FACTOR_LARGE] = 117 resources.getFraction(R.fraction.lb_focus_zoom_factor_large, 1, 1); 118 } 119 } 120 121 private float getScale(View view) { 122 lazyInit(view.getResources()); 123 return sScaleFactor[mScaleIndex]; 124 } 125 126 private void viewFocused(View view, boolean hasFocus) { 127 view.setSelected(hasFocus); 128 FocusAnimator animator = (FocusAnimator) view.getTag(R.id.lb_focus_animator); 129 if (animator == null) { 130 animator = new FocusAnimator(view, getScale(view), DURATION_MS); 131 view.setTag(R.id.lb_focus_animator, animator); 132 } 133 animator.animateFocus(hasFocus, false); 134 } 135 136 @Override 137 public void onItemFocused(View view, boolean hasFocus) { 138 viewFocused(view, hasFocus); 139 } 140 } 141 142 /** 143 * Setup the focus highlight behavior of a focused item in browse list row. 144 * @param adapter adapter of the list row. 145 */ 146 public static void setupBrowseItemFocusHighlight(ItemBridgeAdapter adapter, int zoomIndex) { 147 adapter.setFocusHighlight(new BrowseItemFocusHighlight(zoomIndex)); 148 } 149 150 /** 151 * Setup the focus highlight behavior of a focused item in header list. 152 * @param gridView the header list. 153 */ 154 public static void setupHeaderItemFocusHighlight(VerticalGridView gridView) { 155 if (gridView.getAdapter() instanceof ItemBridgeAdapter) { 156 ((ItemBridgeAdapter) gridView.getAdapter()) 157 .setFocusHighlight(new HeaderItemFocusHighlight(gridView)); 158 } 159 } 160 161 static class HeaderItemFocusHighlight implements FocusHighlight { 162 private static boolean sInitialized; 163 private static float sSelectScale; 164 private static int sDuration; 165 private BaseGridView mGridView; 166 167 HeaderItemFocusHighlight(BaseGridView gridView) { 168 mGridView = gridView; 169 lazyInit(gridView.getContext().getResources()); 170 } 171 172 private static void lazyInit(Resources res) { 173 if (!sInitialized) { 174 sSelectScale = 175 Float.parseFloat(res.getString(R.dimen.lb_browse_header_select_scale)); 176 sDuration = 177 Integer.parseInt(res.getString(R.dimen.lb_browse_header_select_duration)); 178 sInitialized = true; 179 } 180 } 181 182 class HeaderFocusAnimator extends FocusAnimator { 183 184 ItemBridgeAdapter.ViewHolder mViewHolder; 185 HeaderFocusAnimator(View view, float scale, int duration) { 186 super(view, scale, duration); 187 mViewHolder = (ItemBridgeAdapter.ViewHolder) mGridView.getChildViewHolder(view); 188 } 189 190 @Override 191 void setFocusLevel(float level) { 192 Presenter presenter = mViewHolder.getPresenter(); 193 if (presenter instanceof RowHeaderPresenter) { 194 ((RowHeaderPresenter) presenter).setSelectLevel( 195 ((RowHeaderPresenter.ViewHolder) mViewHolder.getViewHolder()), level); 196 } 197 super.setFocusLevel(level); 198 } 199 200 } 201 202 private void viewFocused(View view, boolean hasFocus) { 203 view.setSelected(hasFocus); 204 FocusAnimator animator = (FocusAnimator) view.getTag(R.id.lb_focus_animator); 205 if (animator == null) { 206 animator = new HeaderFocusAnimator(view, sSelectScale, sDuration); 207 view.setTag(R.id.lb_focus_animator, animator); 208 } 209 animator.animateFocus(hasFocus, false); 210 } 211 212 @Override 213 public void onItemFocused(View view, boolean hasFocus) { 214 viewFocused(view, hasFocus); 215 } 216 } 217} 218