1/* 2 * Copyright (C) 2014 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.tv.settings.dialog.old; 18 19import android.animation.Animator; 20import android.os.Bundle; 21import android.view.LayoutInflater; 22import android.view.View; 23import android.view.ViewGroup; 24import android.view.ViewGroup.LayoutParams; 25import android.view.ViewPropertyAnimator; 26import android.view.animation.DecelerateInterpolator; 27 28import com.android.tv.settings.R; 29import com.android.tv.settings.widget.ScrollAdapter; 30import com.android.tv.settings.widget.ScrollAdapterView; 31import com.android.tv.settings.widget.ScrollAdapterView.OnScrollListener; 32 33/** 34 * Fragment which uses a ScrollAdapterView as its basic UI. 35 * <p> 36 * This fragment is meant to be inserted as the action fragment into a {@link DialogActivity}. 37 * <p> 38 * Users can either subclass this or just use listener objects to receive life cycle events. 39 */ 40public class BaseScrollAdapterFragment implements OnScrollListener { 41 private int mAnimationDuration; 42 private final LiteFragment mFragment; 43 44 private ScrollAdapter mAdapter; 45 private ScrollAdapterView mScrollAdapterView; 46 private View mSelectorView; 47 private View mSelectedView = null; 48 private volatile boolean mFadedOut = true; 49 50 public BaseScrollAdapterFragment(LiteFragment fragment) { 51 mFragment = fragment; 52 } 53 54 public View onCreateView(LayoutInflater inflater, ViewGroup container, 55 Bundle savedInstanceState) { 56 View v = inflater.inflate(R.layout.settings_list, container, false); 57 mScrollAdapterView = null; 58 return v; 59 } 60 61 public void onViewCreated(View view, Bundle savedInstanceState) { 62 ensureList(); 63 } 64 65 public boolean hasCreatedView() { 66 if (mFragment == null || mFragment.getView() == null) { 67 return false; 68 } else { 69 return true; 70 } 71 } 72 73 public ScrollAdapterView getScrollAdapterView() { 74 ensureList(); 75 return mScrollAdapterView; 76 } 77 78 public ScrollAdapter getAdapter() { 79 return mAdapter; 80 } 81 82 public void setAdapter(ScrollAdapter adapter) { 83 mAdapter = adapter; 84 if (mScrollAdapterView != null) { 85 mScrollAdapterView.setAdapter(mAdapter); 86 } 87 } 88 89 public void setSelection(int position) { 90 mScrollAdapterView.setSelection(position); 91 } 92 93 public void setSelectionSmooth(int position) { 94 mScrollAdapterView.setSelectionSmooth(position); 95 } 96 97 public int getSelectedItemPosition() { 98 return mScrollAdapterView.getSelectedItemPosition(); 99 } 100 101 public void ensureList() { 102 if (mScrollAdapterView != null) { 103 return; 104 } 105 View root = mFragment.getView(); 106 if (root == null) { 107 throw new IllegalStateException("Content view not created yet."); 108 } 109 if (root instanceof ScrollAdapterView) { 110 mScrollAdapterView = (ScrollAdapterView) root; 111 mSelectorView = null; 112 } else { 113 mScrollAdapterView = (ScrollAdapterView) root.findViewById(R.id.list); 114 if (mScrollAdapterView == null) { 115 throw new IllegalStateException("No scroll adapter view exists."); 116 } 117 mSelectorView = root.findViewById(R.id.selector); 118 } 119 if (mScrollAdapterView != null) { 120 mScrollAdapterView.requestFocusFromTouch(); 121 if (mAdapter != null) { 122 mScrollAdapterView.setAdapter(mAdapter); 123 } 124 if (mSelectorView != null) { 125 mAnimationDuration = mFragment.getActivity() 126 .getResources().getInteger(R.integer.dialog_animation_duration); 127 mScrollAdapterView.addOnScrollListener(this); 128 } 129 } 130 } 131 132 /** 133 * Sets {@link BaseScrollAdapterFragment#mFadedOut} 134 * 135 * {@link BaseScrollAdapterFragment#mFadedOut} is true, iff 136 * {@link BaseScrollAdapterFragment#mSelectorView} has an alpha of 0 137 * (faded out). If false the view either has an alpha of 1 (visible) or 138 * is in the process of animating. 139 */ 140 private class Listener implements Animator.AnimatorListener { 141 private boolean mFadingOut; 142 private boolean mCanceled; 143 144 public Listener(boolean fadingOut) { 145 mFadingOut = fadingOut; 146 } 147 148 @Override 149 public void onAnimationStart(Animator animation) { 150 if(!mFadingOut) { 151 mFadedOut = false; 152 } 153 } 154 155 @Override 156 public void onAnimationEnd(Animator animation) { 157 if (!mCanceled && mFadingOut) { 158 mFadedOut = true; 159 } 160 } 161 162 @Override 163 public void onAnimationCancel(Animator animation) { 164 mCanceled = true; 165 } 166 167 @Override 168 public void onAnimationRepeat(Animator animation) { 169 } 170 } 171 172 // We want to fade in the selector if we've stopped scrolling on it (mainPosition = 0). 173 // If mainPosition is not 0, we want to ensure to dim the selector if we haven't already. 174 // we dim the last highlighted view so that while a user is scrolling, nothing is highlighted. 175 @Override 176 public synchronized void onScrolled(View view, int position, float mainPosition, 177 float secondPosition) { 178 boolean hasFocus = (mainPosition == 0.0); 179 if (hasFocus) { 180 if (view != null) { 181 // The selector starts with a height of 0. In order to scale up 182 // from 183 // 0 we first need the set the height to 1 and scale form there. 184 int selectorHeight = mSelectorView.getHeight(); 185 if (selectorHeight == 0) { 186 LayoutParams lp = mSelectorView.getLayoutParams(); 187 lp.height = selectorHeight = mFragment.getActivity().getResources() 188 .getDimensionPixelSize(R.dimen.action_fragment_selector_min_height); 189 mSelectorView.setLayoutParams(lp); 190 } 191 float scaleY = (float) view.getHeight() / selectorHeight; 192 ViewPropertyAnimator animation = mSelectorView.animate() 193 .alpha(1f) 194 .setListener(new Listener(false)) 195 .setDuration(mAnimationDuration) 196 .setInterpolator(new DecelerateInterpolator(2f)); 197 if (mFadedOut) { 198 // selector is completely faded out, so we can just scale 199 // before fading in. 200 mSelectorView.setScaleY(scaleY); 201 } else { 202 // selector is not faded out, so we must animate the scale 203 // as we fade in. 204 animation.scaleY(scaleY); 205 } 206 animation.start(); 207 mSelectedView = view; 208 } else { 209 LayoutParams lp = mSelectorView.getLayoutParams(); 210 lp.height = 0; 211 mSelectorView.setLayoutParams(lp); 212 } 213 } else if (mSelectedView != null) { 214 mSelectorView.animate() 215 .alpha(0f) 216 .setDuration(mAnimationDuration) 217 .setInterpolator(new DecelerateInterpolator(2f)) 218 .setListener(new Listener(true)) 219 .start(); 220 mSelectedView = null; 221 } 222 } 223} 224