DetailsOverviewRowPresenter.java revision 819b4e55bcf37847548a55c5dac0dfa8323975f6
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.content.Context; 17import android.graphics.Color; 18import android.support.v17.leanback.R; 19import android.support.v7.widget.RecyclerView; 20import android.util.Log; 21import android.util.TypedValue; 22import android.view.LayoutInflater; 23import android.view.View; 24import android.view.ViewGroup; 25import android.widget.FrameLayout; 26import android.widget.ImageView; 27 28import java.util.Collection; 29 30/** 31 * A DetailsOverviewRowPresenter renders a {@link DetailsOverviewRow} to display an 32 * overview of an item. Typically this row will be the first row in a fragment 33 * such as the {@link android.support.v17.leanback.app.DetailsFragment 34 * DetailsFragment}. 35 * 36 * <p>The detailed description is rendered using a {@link Presenter}. 37 */ 38public class DetailsOverviewRowPresenter extends RowPresenter { 39 40 private static final String TAG = "DetailsOverviewRowPresenter"; 41 private static final boolean DEBUG = false; 42 43 private static final int MORE_ACTIONS_FADE_MS = 100; 44 45 /** 46 * A ViewHolder for the DetailsOverviewRow. 47 */ 48 public static class ViewHolder extends RowPresenter.ViewHolder { 49 final ImageView mImageView; 50 final FrameLayout mDetailsDescriptionFrame; 51 final HorizontalGridView mActionsRow; 52 Presenter.ViewHolder mDetailsDescriptionViewHolder; 53 int mNumItems; 54 boolean mShowMoreRight; 55 boolean mShowMoreLeft; 56 57 void bind(ItemBridgeAdapter bridgeAdapter) { 58 mNumItems = bridgeAdapter.getItemCount(); 59 bridgeAdapter.setAdapterListener(mAdapterListener); 60 61 mShowMoreRight = false; 62 mShowMoreLeft = true; 63 showMoreLeft(false); 64 } 65 66 final View.OnLayoutChangeListener mLayoutChangeListener = 67 new View.OnLayoutChangeListener() { 68 69 @Override 70 public void onLayoutChange(View v, int left, int top, int right, 71 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 72 if (DEBUG) Log.v(TAG, "onLayoutChange " + v); 73 checkFirstAndLastPosition(false); 74 } 75 }; 76 77 final ItemBridgeAdapter.AdapterListener mAdapterListener = 78 new ItemBridgeAdapter.AdapterListener() { 79 80 @Override 81 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) { 82 // Remove first to ensure we don't add ourselves more than once. 83 viewHolder.itemView.removeOnLayoutChangeListener(mLayoutChangeListener); 84 viewHolder.itemView.addOnLayoutChangeListener(mLayoutChangeListener); 85 } 86 @Override 87 public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder viewHolder) { 88 viewHolder.itemView.removeOnLayoutChangeListener(mLayoutChangeListener); 89 checkFirstAndLastPosition(false); 90 } 91 }; 92 93 final RecyclerView.OnScrollListener mScrollListener = 94 new RecyclerView.OnScrollListener() { 95 96 @Override 97 public void onScrollStateChanged(int newState) { 98 } 99 @Override 100 public void onScrolled(int dx, int dy) { 101 checkFirstAndLastPosition(true); 102 } 103 }; 104 105 private int getViewCenter(View view) { 106 return (view.getRight() - view.getLeft()) / 2; 107 } 108 109 private void checkFirstAndLastPosition(boolean fromScroll) { 110 RecyclerView.ViewHolder viewHolder; 111 112 viewHolder = mActionsRow.findViewHolderForPosition(mNumItems - 1); 113 boolean showRight = (viewHolder == null || 114 viewHolder.itemView.getRight() > mActionsRow.getWidth()); 115 116 viewHolder = mActionsRow.findViewHolderForPosition(0); 117 boolean showLeft = (viewHolder == null || viewHolder.itemView.getLeft() < 0); 118 119 if (DEBUG) Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll + 120 " showRight " + showRight + " showLeft " + showLeft); 121 122 showMoreRight(showRight); 123 showMoreLeft(showLeft); 124 } 125 126 private void showMoreLeft(boolean show) { 127 if (show != mShowMoreLeft) { 128 mActionsRow.setFadingLeftEdge(show); 129 mShowMoreLeft = show; 130 } 131 } 132 133 private void showMoreRight(boolean show) { 134 if (show != mShowMoreRight) { 135 mActionsRow.setFadingRightEdge(show); 136 mShowMoreRight = show; 137 } 138 } 139 140 /** 141 * Constructor for the ViewHolder. 142 * 143 * @param rootView The root View that this view holder will be attached 144 * to. 145 */ 146 public ViewHolder(View rootView) { 147 super(rootView); 148 mImageView = (ImageView) rootView.findViewById(R.id.details_overview_image); 149 mDetailsDescriptionFrame = 150 (FrameLayout) rootView.findViewById(R.id.details_overview_description); 151 mActionsRow = 152 (HorizontalGridView) rootView.findViewById(R.id.details_overview_actions); 153 mActionsRow.setOnScrollListener(mScrollListener); 154 155 final int fadeLength = rootView.getResources().getDimensionPixelSize( 156 R.dimen.lb_details_overview_actions_fade_size); 157 mActionsRow.setFadingRightEdgeLength(fadeLength); 158 mActionsRow.setFadingLeftEdgeLength(fadeLength); 159 } 160 } 161 162 private final Presenter mDetailsPresenter; 163 private final ActionPresenterSelector mActionPresenterSelector; 164 private final ItemBridgeAdapter mActionBridgeAdapter; 165 private int mBackgroundColor = Color.TRANSPARENT; 166 private boolean mBackgroundColorSet; 167 private boolean mIsStyleLarge = true; 168 169 /** 170 * Constructor for a DetailsOverviewRowPresenter. 171 * 172 * @param detailsPresenter The {@link Presenter} used to render the detailed 173 * description of the row. 174 */ 175 public DetailsOverviewRowPresenter(Presenter detailsPresenter) { 176 setHeaderPresenter(null); 177 setSelectEffectEnabled(false); 178 mDetailsPresenter = detailsPresenter; 179 mActionPresenterSelector = new ActionPresenterSelector(); 180 mActionBridgeAdapter = new ItemBridgeAdapter(); 181 } 182 183 /** 184 * Sets the listener for Action click events. 185 */ 186 public void setOnActionClickedListener(OnActionClickedListener listener) { 187 mActionPresenterSelector.setOnActionClickedListener(listener); 188 } 189 190 /** 191 * Gets the listener for Action click events. 192 */ 193 public OnActionClickedListener getOnActionClickedListener() { 194 return mActionPresenterSelector.getOnActionClickedListener(); 195 } 196 197 /** 198 * Sets the background color. If not set, a default from the theme will be used. 199 */ 200 public void setBackgroundColor(int color) { 201 mBackgroundColor = color; 202 mBackgroundColorSet = true; 203 } 204 205 /** 206 * Returns the background color. If no background color was set, transparent 207 * is returned. 208 */ 209 public int getBackgroundColor() { 210 return mBackgroundColor; 211 } 212 213 /** 214 * Sets the layout style to be large or small. This affects the height of 215 * the overview, including the text description. The default is large. 216 */ 217 public void setStyleLarge(boolean large) { 218 mIsStyleLarge = large; 219 } 220 221 /** 222 * Returns true if the layout style is large. 223 */ 224 public boolean isStyleLarge() { 225 return mIsStyleLarge; 226 } 227 228 private int getDefaultBackgroundColor(Context context) { 229 TypedValue outValue = new TypedValue(); 230 context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true); 231 return context.getResources().getColor(outValue.resourceId); 232 } 233 234 @Override 235 protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { 236 View v = LayoutInflater.from(parent.getContext()) 237 .inflate(R.layout.lb_details_overview, parent, false); 238 ViewHolder vh = new ViewHolder(v); 239 240 vh.mDetailsDescriptionViewHolder = 241 mDetailsPresenter.onCreateViewHolder(vh.mDetailsDescriptionFrame); 242 vh.mDetailsDescriptionFrame.addView(vh.mDetailsDescriptionViewHolder.view); 243 244 initDetailsOverview(vh); 245 246 return vh; 247 } 248 249 private void initDetailsOverview(ViewHolder vh) { 250 int resId = mIsStyleLarge ? R.dimen.lb_details_overview_height_large : 251 R.dimen.lb_details_overview_height_small; 252 253 View overview = vh.view.findViewById(R.id.details_overview); 254 ViewGroup.LayoutParams lp = overview.getLayoutParams(); 255 lp.height = overview.getResources().getDimensionPixelSize(resId); 256 overview.setLayoutParams(lp); 257 258 overview.setBackgroundColor(mBackgroundColorSet ? 259 mBackgroundColor : getDefaultBackgroundColor(overview.getContext())); 260 ShadowHelper.getInstance().setZ(overview, 0f); 261 262 // Max width to make a square 263 ImageView image = (ImageView) vh.view.findViewById(R.id.details_overview_image); 264 image.setMaxWidth(lp.height); 265 } 266 267 @Override 268 protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) { 269 super.onBindRowViewHolder(holder, item); 270 271 DetailsOverviewRow row = (DetailsOverviewRow) item; 272 ViewHolder vh = (ViewHolder) holder; 273 if (row.getImageDrawable() != null) { 274 vh.mImageView.setImageDrawable(row.getImageDrawable()); 275 } 276 if (vh.mDetailsDescriptionViewHolder == null) { 277 } 278 mDetailsPresenter.onBindViewHolder(vh.mDetailsDescriptionViewHolder, row); 279 280 mActionBridgeAdapter.clear(); 281 ArrayObjectAdapter aoa = new ArrayObjectAdapter(mActionPresenterSelector); 282 aoa.addAll(0, (Collection)row.getActions()); 283 284 mActionBridgeAdapter.setAdapter(aoa); 285 vh.mActionsRow.setAdapter(mActionBridgeAdapter); 286 287 vh.bind(mActionBridgeAdapter); 288 } 289 290 @Override 291 protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) { 292 super.onUnbindRowViewHolder(holder); 293 294 ViewHolder vh = (ViewHolder) holder; 295 if (vh.mDetailsDescriptionViewHolder != null) { 296 mDetailsPresenter.onUnbindViewHolder(vh.mDetailsDescriptionViewHolder); 297 } 298 299 vh.mActionsRow.setAdapter(null); 300 } 301} 302