ItemBridgeAdapter.java revision cf94c5fa8ae8edb7e26a623133207415ceeed187
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.v7.widget.RecyclerView; 17import android.support.v17.leanback.R; 18import android.util.Log; 19import android.view.View; 20import android.view.ViewGroup; 21 22import java.util.ArrayList; 23 24/** 25 * Bridge from Presenter to RecyclerView.Adapter. Public to allow use by third 26 * party presenters. 27 */ 28public class ItemBridgeAdapter extends RecyclerView.Adapter { 29 private static final String TAG = "ItemBridgeAdapter"; 30 private static final boolean DEBUG = false; 31 32 /** 33 * Interface for listening to view holder operations. 34 */ 35 public static class AdapterListener { 36 public void onAddPresenter(Presenter presenter) { 37 } 38 public void onCreate(ViewHolder viewHolder) { 39 } 40 public void onBind(ViewHolder viewHolder) { 41 } 42 public void onUnbind(ViewHolder viewHolder) { 43 } 44 public void onAttachedToWindow(ViewHolder viewHolder) { 45 } 46 public void onDetachedFromWindow(ViewHolder viewHolder) { 47 } 48 } 49 50 private ObjectAdapter mAdapter; 51 private PresenterSelector mPresenterSelector; 52 private FocusHighlight mFocusHighlight; 53 private AdapterListener mAdapterListener; 54 private ArrayList<Presenter> mPresenters = new ArrayList<Presenter>(); 55 56 final class OnFocusChangeListener implements View.OnFocusChangeListener { 57 View.OnFocusChangeListener mChainedListener; 58 59 @Override 60 public void onFocusChange(View view, boolean hasFocus) { 61 if (DEBUG) Log.v(TAG, "onFocusChange " + hasFocus + " " + view 62 + " mFocusHighlight" + mFocusHighlight); 63 ViewHolder viewHolder = getChildViewHolder(view); 64 if (mFocusHighlight != null) { 65 mFocusHighlight.onItemFocused(view, viewHolder.mItem, hasFocus); 66 } 67 if (mChainedListener != null) { 68 mChainedListener.onFocusChange(view, hasFocus); 69 } 70 } 71 } 72 73 public class ViewHolder extends RecyclerView.ViewHolder { 74 final Presenter mPresenter; 75 final Presenter.ViewHolder mHolder; 76 final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener(); 77 Object mItem; 78 Object mExtraObject; 79 80 /** 81 * Get {@link Presenter}. 82 */ 83 public final Presenter getPresenter() { 84 return mPresenter; 85 } 86 87 /** 88 * Get {@link Presenter.ViewHolder}. 89 */ 90 public final Presenter.ViewHolder getViewHolder() { 91 return mHolder; 92 } 93 94 /** 95 * Get currently bound object. 96 */ 97 public final Object getItem() { 98 return mItem; 99 } 100 101 /** 102 * Get extra object associated with the view. Developer can attach 103 * any customized UI object in addition to {@link Presenter.ViewHolder}. 104 * A typical use case is attaching an animator object. 105 */ 106 public final Object getExtraObject() { 107 return mExtraObject; 108 } 109 110 /** 111 * Set extra object associated with the view. Developer can attach 112 * any customized UI object in addition to {@link Presenter.ViewHolder}. 113 * A typical use case is attaching an animator object. 114 */ 115 public void setExtraObject(Object object) { 116 mExtraObject = object; 117 } 118 119 ViewHolder(Presenter presenter, Presenter.ViewHolder holder) { 120 super(holder.view); 121 mPresenter = presenter; 122 mHolder = holder; 123 } 124 } 125 126 private ObjectAdapter.DataObserver mDataObserver = new ObjectAdapter.DataObserver() { 127 @Override 128 public void onChanged() { 129 ItemBridgeAdapter.this.notifyDataSetChanged(); 130 } 131 @Override 132 public void onItemRangeChanged(int positionStart, int itemCount) { 133 ItemBridgeAdapter.this.notifyItemRangeChanged(positionStart, itemCount); 134 } 135 @Override 136 public void onItemRangeInserted(int positionStart, int itemCount) { 137 ItemBridgeAdapter.this.notifyItemRangeInserted(positionStart, itemCount); 138 } 139 @Override 140 public void onItemRangeRemoved(int positionStart, int itemCount) { 141 ItemBridgeAdapter.this.notifyItemRangeRemoved(positionStart, itemCount); 142 } 143 }; 144 145 public ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector) { 146 setAdapter(adapter); 147 mPresenterSelector = presenterSelector; 148 } 149 150 public ItemBridgeAdapter() { 151 } 152 153 private ViewHolder getChildViewHolder(View view) { 154 RecyclerView recyclerView = (RecyclerView) view.getParent(); 155 return (ViewHolder) recyclerView.getChildViewHolder(view); 156 } 157 158 public void setAdapter(ObjectAdapter adapter) { 159 if (mAdapter != null) { 160 mAdapter.unregisterObserver(mDataObserver); 161 } 162 mAdapter = adapter; 163 if (mAdapter == null) { 164 return; 165 } 166 167 mAdapter.registerObserver(mDataObserver); 168 setHasStableIds(mAdapter.hasStableIds()); 169 } 170 171 void setFocusHighlight(FocusHighlight listener) { 172 mFocusHighlight = listener; 173 if (DEBUG) Log.v(TAG, "setFocusHighlight " + mFocusHighlight); 174 } 175 176 public void clear() { 177 setAdapter(null); 178 } 179 180 @Override 181 public int getItemCount() { 182 return mAdapter.size(); 183 } 184 185 @Override 186 public int getItemViewType(int position) { 187 PresenterSelector presenterSelector = mPresenterSelector != null ? 188 mPresenterSelector : mAdapter.getPresenterSelector(); 189 Object item = mAdapter.get(position); 190 Presenter presenter = presenterSelector.getPresenter(item); 191 int type = mPresenters.indexOf(presenter); 192 if (type < 0) { 193 mPresenters.add(presenter); 194 type = mPresenters.indexOf(presenter); 195 if (mAdapterListener != null) { 196 mAdapterListener.onAddPresenter(presenter); 197 } 198 } 199 return type; 200 } 201 202 /** 203 * {@link View.OnFocusChangeListener} that assigned in 204 * {@link Presenter#onCreateViewHolder(ViewGroup)} may be chained, user should never change 205 * {@link View.OnFocusChangeListener} after that. 206 */ 207 @Override 208 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 209 if (DEBUG) Log.v(TAG, "onCreateViewHolder viewType " + viewType); 210 Presenter presenter = mPresenters.get(viewType); 211 ViewHolder viewHolder = new ViewHolder(presenter, presenter.onCreateViewHolder(parent)); 212 if (mAdapterListener != null) { 213 mAdapterListener.onCreate(viewHolder); 214 } 215 View view = viewHolder.mHolder.view; 216 if (view != null) { 217 viewHolder.mFocusChangeListener.mChainedListener = view.getOnFocusChangeListener(); 218 view.setOnFocusChangeListener(viewHolder.mFocusChangeListener); 219 } 220 return viewHolder; 221 } 222 223 public void setAdapterListener(AdapterListener listener) { 224 mAdapterListener = listener; 225 } 226 227 @Override 228 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 229 if (DEBUG) Log.v(TAG, "onBindViewHolder position " + position); 230 ViewHolder viewHolder = (ViewHolder) holder; 231 viewHolder.mItem = mAdapter.get(position); 232 233 viewHolder.mPresenter.onBindViewHolder(viewHolder.mHolder, viewHolder.mItem); 234 235 if (mAdapterListener != null) { 236 mAdapterListener.onBind(viewHolder); 237 } 238 } 239 240 @Override 241 public void onViewRecycled(RecyclerView.ViewHolder holder) { 242 ViewHolder viewHolder = (ViewHolder) holder; 243 viewHolder.mPresenter.onUnbindViewHolder(viewHolder.mHolder); 244 245 viewHolder.mItem = null; 246 247 if (mAdapterListener != null) { 248 mAdapterListener.onUnbind(viewHolder); 249 } 250 } 251 252 @Override 253 public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 254 ViewHolder viewHolder = (ViewHolder) holder; 255 if (mAdapterListener != null) { 256 mAdapterListener.onAttachedToWindow(viewHolder); 257 } 258 viewHolder.mPresenter.onViewAttachedToWindow(viewHolder.mHolder); 259 } 260 261 @Override 262 public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { 263 ViewHolder viewHolder = (ViewHolder) holder; 264 viewHolder.mPresenter.onViewDetachedFromWindow(viewHolder.mHolder); 265 if (mAdapterListener != null) { 266 mAdapterListener.onDetachedFromWindow(viewHolder); 267 } 268 } 269 270 @Override 271 public long getItemId(int position) { 272 return mAdapter.getId(position); 273 } 274 275} 276