VerticalGridFragment.java revision 4c0f3062b5edd9750351068f46e5270bb220091d
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.app; 15 16import android.support.v17.leanback.R; 17import android.support.v17.leanback.widget.Row; 18import android.support.v17.leanback.widget.TitleView; 19import android.support.v17.leanback.widget.VerticalGridPresenter; 20import android.support.v17.leanback.widget.ObjectAdapter; 21import android.support.v17.leanback.widget.OnItemClickedListener; 22import android.support.v17.leanback.widget.OnItemSelectedListener; 23import android.support.v17.leanback.widget.SearchOrbView; 24import android.app.Fragment; 25import android.graphics.drawable.Drawable; 26import android.os.Bundle; 27import android.util.Log; 28import android.view.LayoutInflater; 29import android.view.View; 30import android.view.ViewGroup; 31import android.view.ViewGroup.MarginLayoutParams; 32import android.widget.ImageView; 33import android.widget.TextView; 34 35/** 36 * A fragment for creating leanback vertical grids. 37 * 38 * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and 39 * an {@link ObjectAdapter}. 40 */ 41public class VerticalGridFragment extends Fragment { 42 private static final String TAG = "VerticalGridFragment"; 43 private static boolean DEBUG = false; 44 45 private BrowseFrameLayout mBrowseFrame; 46 private String mTitle; 47 private Drawable mBadgeDrawable; 48 private ObjectAdapter mAdapter; 49 private VerticalGridPresenter mGridPresenter; 50 private VerticalGridPresenter.ViewHolder mGridViewHolder; 51 private OnItemSelectedListener mOnItemSelectedListener; 52 private OnItemClickedListener mOnItemClickedListener; 53 private View.OnClickListener mExternalOnSearchClickedListener; 54 private int mSelectedPosition = -1; 55 56 private TitleView mTitleView; 57 private int mSearchAffordanceColor; 58 private boolean mSearchAffordanceColorSet; 59 private boolean mShowingTitle = true; 60 61 // transition related 62 private static TransitionHelper sTransitionHelper = TransitionHelper.getInstance(); 63 private Object mTitleUpTransition; 64 private Object mTitleDownTransition; 65 private Object mSceneWithTitle; 66 private Object mSceneWithoutTitle; 67 68 /** 69 * Sets the badge drawable displayed in the title area. 70 */ 71 public void setBadgeDrawable(Drawable drawable) { 72 if (drawable != mBadgeDrawable) { 73 mBadgeDrawable = drawable; 74 if (mTitleView != null) { 75 mTitleView.setBadgeDrawable(drawable); 76 } 77 } 78 } 79 80 /** 81 * Returns the badge drawable. 82 */ 83 public Drawable getBadgeDrawable() { 84 return mBadgeDrawable; 85 } 86 87 /** 88 * Sets a title for the fragment. 89 */ 90 public void setTitle(String title) { 91 mTitle = title; 92 if (mTitleView != null) { 93 mTitleView.setTitle(mTitle); 94 } 95 } 96 97 /** 98 * Returns the title for the fragment. 99 */ 100 public String getTitle() { 101 return mTitle; 102 } 103 104 /** 105 * Sets the grid presenter. 106 */ 107 public void setGridPresenter(VerticalGridPresenter gridPresenter) { 108 if (gridPresenter == null) { 109 throw new IllegalArgumentException("Grid presenter may not be null"); 110 } 111 mGridPresenter = gridPresenter; 112 mGridPresenter.setOnItemSelectedListener(mRowSelectedListener); 113 if (mOnItemClickedListener != null) { 114 mGridPresenter.setOnItemClickedListener(mOnItemClickedListener); 115 } 116 } 117 118 /** 119 * Returns the grid presenter. 120 */ 121 public VerticalGridPresenter getGridPresenter() { 122 return mGridPresenter; 123 } 124 125 /** 126 * Sets the object adapter for the fragment. 127 */ 128 public void setAdapter(ObjectAdapter adapter) { 129 mAdapter = adapter; 130 updateAdapter(); 131 } 132 133 /** 134 * Returns the object adapter. 135 */ 136 public ObjectAdapter getAdapter() { 137 return mAdapter; 138 } 139 140 final private OnItemSelectedListener mRowSelectedListener = new OnItemSelectedListener() { 141 @Override 142 public void onItemSelected(Object item, Row row) { 143 int position = mGridViewHolder.getGridView().getSelectedPosition(); 144 if (DEBUG) Log.v(TAG, "row selected position " + position); 145 onRowSelected(position); 146 if (mOnItemSelectedListener != null) { 147 mOnItemSelectedListener.onItemSelected(item, row); 148 } 149 } 150 }; 151 152 /** 153 * Sets an item selection listener. 154 */ 155 public void setOnItemSelectedListener(OnItemSelectedListener listener) { 156 mOnItemSelectedListener = listener; 157 } 158 159 private void onRowSelected(int position) { 160 if (position != mSelectedPosition) { 161 if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(position)) { 162 // if has no sibling in front of it, show title 163 if (!mShowingTitle) { 164 sTransitionHelper.runTransition(mSceneWithTitle, mTitleDownTransition); 165 mShowingTitle = true; 166 } 167 } else if (mShowingTitle) { 168 sTransitionHelper.runTransition(mSceneWithoutTitle, mTitleUpTransition); 169 mShowingTitle = false; 170 } 171 mSelectedPosition = position; 172 } 173 } 174 175 /** 176 * Sets an item clicked listener. 177 */ 178 public void setOnItemClickedListener(OnItemClickedListener listener) { 179 mOnItemClickedListener = listener; 180 if (mGridPresenter != null) { 181 mGridPresenter.setOnItemClickedListener(mOnItemClickedListener); 182 } 183 } 184 185 /** 186 * Returns the item clicked listener. 187 */ 188 public OnItemClickedListener getOnItemClickedListener() { 189 return mOnItemClickedListener; 190 } 191 192 /** 193 * Sets a click listener for the search affordance. 194 * 195 * <p>The presence of a listener will change the visibility of the search 196 * affordance in the title area. When set to non-null, the title area will 197 * contain a call to search action. 198 * 199 * <p>The listener's onClick method will be invoked when the user clicks on 200 * the search action. 201 * 202 * @param listener The listener to invoke when the search affordance is 203 * clicked, or null to hide the search affordance. 204 */ 205 public void setOnSearchClickedListener(View.OnClickListener listener) { 206 mExternalOnSearchClickedListener = listener; 207 if (mTitleView != null) { 208 mTitleView.setOnSearchClickedListener(listener); 209 } 210 } 211 212 /** 213 * Sets the color used to draw the search affordance. 214 */ 215 public void setSearchAffordanceColor(int color) { 216 mSearchAffordanceColor = color; 217 mSearchAffordanceColorSet = true; 218 if (mTitleView != null) { 219 mTitleView.setSearchAffordanceColor(mSearchAffordanceColor); 220 } 221 } 222 223 /** 224 * Returns the color used to draw the search affordance. 225 */ 226 public int getSearchAffordanceColor() { 227 if (mSearchAffordanceColorSet) { 228 return mSearchAffordanceColor; 229 } 230 if (mTitleView == null) { 231 throw new IllegalStateException("Fragment views not yet created"); 232 } 233 return mTitleView.getSearchAffordanceColor(); 234 } 235 236 237 private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener = 238 new BrowseFrameLayout.OnFocusSearchListener() { 239 @Override 240 public View onFocusSearch(View focused, int direction) { 241 if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction); 242 243 final View searchOrbView = mTitleView.getSearchAffordanceView(); 244 if (focused == searchOrbView && ( 245 direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT)) { 246 return mGridViewHolder.view; 247 248 } else if (focused != searchOrbView && searchOrbView.getVisibility() == View.VISIBLE 249 && direction == View.FOCUS_UP) { 250 return searchOrbView; 251 252 } else { 253 return null; 254 } 255 } 256 }; 257 258 @Override 259 public View onCreateView(LayoutInflater inflater, ViewGroup container, 260 Bundle savedInstanceState) { 261 ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment, 262 container, false); 263 264 mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame); 265 mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener); 266 267 mTitleView = (TitleView) root.findViewById(R.id.browse_title_group); 268 mTitleView.setBadgeDrawable(mBadgeDrawable); 269 mTitleView.setTitle(mTitle); 270 if (mSearchAffordanceColorSet) { 271 mTitleView.setSearchAffordanceColor(mSearchAffordanceColor); 272 } 273 if (mExternalOnSearchClickedListener != null) { 274 mTitleView.setOnSearchClickedListener(mExternalOnSearchClickedListener); 275 } 276 277 mSceneWithTitle = sTransitionHelper.createScene(root, new Runnable() { 278 @Override 279 public void run() { 280 TitleTransitionHelper.showTitle(mTitleView, true); 281 } 282 }); 283 mSceneWithoutTitle = sTransitionHelper.createScene(root, new Runnable() { 284 @Override 285 public void run() { 286 TitleTransitionHelper.showTitle(mTitleView, false); 287 } 288 }); 289 mTitleUpTransition = TitleTransitionHelper.createTransitionTitleUp(sTransitionHelper); 290 mTitleDownTransition = TitleTransitionHelper.createTransitionTitleDown(sTransitionHelper); 291 sTransitionHelper.excludeChildren(mTitleUpTransition, R.id.browse_grid_dock, true); 292 sTransitionHelper.excludeChildren(mTitleDownTransition, R.id.browse_grid_dock, true); 293 294 return root; 295 } 296 297 @Override 298 public void onViewCreated(View view, Bundle savedInstanceState) { 299 ViewGroup gridDock = (ViewGroup) view.findViewById(R.id.browse_grid_dock); 300 mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock); 301 gridDock.addView(mGridViewHolder.view); 302 303 updateAdapter(); 304 } 305 306 @Override 307 public void onStart() { 308 super.onStart(); 309 mGridViewHolder.getGridView().requestFocus(); 310 } 311 312 @Override 313 public void onDestroyView() { 314 super.onDestroyView(); 315 mGridViewHolder = null; 316 } 317 318 /** 319 * Sets the selected item position. 320 */ 321 public void setSelectedPosition(int position) { 322 mSelectedPosition = position; 323 if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) { 324 mGridViewHolder.getGridView().setSelectedPositionSmooth(position); 325 } 326 } 327 328 private void updateAdapter() { 329 if (mGridViewHolder != null) { 330 mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter); 331 if (mSelectedPosition != -1) { 332 mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition); 333 } 334 } 335 } 336} 337