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