GlifRecyclerLayout.java revision 2286e48a268aaa0dc57b93b878c3a632c627acec
1b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam/* 2b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * Copyright (C) 2015 The Android Open Source Project 3b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * 4b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * Licensed under the Apache License, Version 2.0 (the "License"); 5b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * you may not use this file except in compliance with the License. 6b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * You may obtain a copy of the License at 7b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * 8b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * http://www.apache.org/licenses/LICENSE-2.0 9b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * 10b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * Unless required by applicable law or agreed to in writing, software 11b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * distributed under the License is distributed on an "AS IS" BASIS, 12b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * See the License for the specific language governing permissions and 14b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * limitations under the License. 15b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam */ 16b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 17b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lampackage com.android.setupwizardlib; 18b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 19b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.annotation.TargetApi; 20b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.content.Context; 21b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.content.res.TypedArray; 22180360409c9e4e9163c670ff48663244b4057eafMaurice Lamimport android.graphics.drawable.Drawable; 23180360409c9e4e9163c670ff48663244b4057eafMaurice Lamimport android.os.Build; 24b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.os.Build.VERSION_CODES; 25b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.support.v7.widget.LinearLayoutManager; 26b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.support.v7.widget.RecyclerView; 27b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.util.AttributeSet; 28b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.view.LayoutInflater; 29b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.view.View; 30b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.view.ViewGroup; 31b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.widget.ImageView; 32b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport android.widget.TextView; 33b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 34b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.ItemGroup; 35b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.ItemInflater; 36b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.items.RecyclerItemAdapter; 37180360409c9e4e9163c670ff48663244b4057eafMaurice Lamimport com.android.setupwizardlib.util.DrawableLayoutDirectionHelper; 38b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lamimport com.android.setupwizardlib.view.HeaderRecyclerView; 39b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 40b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam/** 41b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * A GLIF themed layout with a RecyclerView. {@code android:entries} can also be used to specify an 42b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam * {@link com.android.setupwizardlib.items.ItemHierarchy} to be used with this layout in XML. 43b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam */ 44b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lampublic class GlifRecyclerLayout extends GlifLayout { 45b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 46b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam private RecyclerView mRecyclerView; 47b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam private TextView mHeaderTextView; 48b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam private ImageView mIconView; 49180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private DividerItemDecoration mDividerDecoration; 50180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private Drawable mDefaultDivider; 51180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private Drawable mDivider; 52180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private int mDividerInset; 53b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 54b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context) { 55b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam this(context, 0, 0); 56b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 57b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 58b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, int template) { 59b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam this(context, template, 0); 60b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 61b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 62b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, int template, int containerId) { 63b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam super(context, template, containerId); 64b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam init(context, null, 0); 65b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 66b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 67b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, AttributeSet attrs) { 68b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam super(context, attrs); 69b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam init(context, attrs, 0); 70b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 71b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 72b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @TargetApi(VERSION_CODES.HONEYCOMB) 73b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public GlifRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) { 74b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam super(context, attrs, defStyleAttr); 75b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam init(context, attrs, defStyleAttr); 76b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 77b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 78b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam private void init(Context context, AttributeSet attrs, int defStyleAttr) { 79b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam final TypedArray a = context.obtainStyledAttributes(attrs, 80b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam R.styleable.SuwGlifRecyclerLayout, defStyleAttr, 0); 81b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam final int xml = a.getResourceId(R.styleable.SuwGlifRecyclerLayout_android_entries, 0); 82b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (xml != 0) { 83b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam final ItemGroup inflated = (ItemGroup) new ItemInflater(context).inflate(xml); 842286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini RecyclerItemAdapter adapter = new RecyclerItemAdapter(inflated); 852286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini adapter.setHasStableIds(a.getBoolean( 862286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini R.styleable.SuwGlifRecyclerLayout_suwHasStableIds, false)); 872286e48a268aaa0dc57b93b878c3a632c627acecUdam Saini setAdapter(adapter); 88b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 89180360409c9e4e9163c670ff48663244b4057eafMaurice Lam int dividerInset = 90180360409c9e4e9163c670ff48663244b4057eafMaurice Lam a.getDimensionPixelSize(R.styleable.SuwGlifRecyclerLayout_suwDividerInset, 0); 91180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (dividerInset == 0) { 92180360409c9e4e9163c670ff48663244b4057eafMaurice Lam dividerInset = getResources() 93180360409c9e4e9163c670ff48663244b4057eafMaurice Lam .getDimensionPixelSize(R.dimen.suw_items_icon_divider_inset); 94180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 95180360409c9e4e9163c670ff48663244b4057eafMaurice Lam setDividerInset(dividerInset); 96b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam a.recycle(); 97b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 98b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 99b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 100180360409c9e4e9163c670ff48663244b4057eafMaurice Lam protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 101180360409c9e4e9163c670ff48663244b4057eafMaurice Lam super.onLayout(changed, left, top, right, bottom); 102180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (mDivider == null) { 103180360409c9e4e9163c670ff48663244b4057eafMaurice Lam // Update divider in case layout direction has just been resolved 104180360409c9e4e9163c670ff48663244b4057eafMaurice Lam updateDivider(); 105180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 106180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 107180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 108180360409c9e4e9163c670ff48663244b4057eafMaurice Lam @Override 109b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected View onInflateTemplate(LayoutInflater inflater, int template) { 110b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (template == 0) { 111b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam template = R.layout.suw_glif_recycler_template; 112b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 113b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return super.onInflateTemplate(inflater, template); 114b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 115b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 116b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 117b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected ViewGroup findContainer(int containerId) { 118b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (containerId == 0) { 119b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam containerId = R.id.suw_recycler_view; 120b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 121b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return super.findContainer(containerId); 122b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 123b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 124b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 125b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected void onTemplateInflated() { 126180360409c9e4e9163c670ff48663244b4057eafMaurice Lam final Context context = getContext(); 127b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam mRecyclerView = (RecyclerView) findViewById(R.id.suw_recycler_view); 128180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mRecyclerView.setLayoutManager(new LinearLayoutManager(context)); 129b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam if (mRecyclerView instanceof HeaderRecyclerView) { 130b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam final View header = ((HeaderRecyclerView) mRecyclerView).getHeader(); 131b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam mHeaderTextView = (TextView) header.findViewById(R.id.suw_layout_title); 132b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam mIconView = (ImageView) header.findViewById(R.id.suw_layout_icon); 133b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 134180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDividerDecoration = DividerItemDecoration.getDefault(context); 135180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mRecyclerView.addItemDecoration(mDividerDecoration); 136b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 137b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 138b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 139b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected TextView getHeaderTextView() { 140b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return mHeaderTextView; 141b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 142b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 143b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam @Override 144b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam protected ImageView getIconView() { 145b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return mIconView; 146b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 147b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 148b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public RecyclerView getRecyclerView() { 149b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam return mRecyclerView; 150b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 151b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 152b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public void setAdapter(RecyclerView.Adapter adapter) { 153b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam getRecyclerView().setAdapter(adapter); 154b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 155b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam 156b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam public RecyclerView.Adapter getAdapter() { 1575a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam final RecyclerView.Adapter adapter = getRecyclerView().getAdapter(); 1585a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam if (adapter instanceof HeaderRecyclerView.HeaderAdapter) { 1595a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam return ((HeaderRecyclerView.HeaderAdapter) adapter).getWrappedAdapter(); 1605a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam } 1615a4d6cdfb63240c41527ba80b7baddba8933d770Maurice Lam return adapter; 162b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam } 163180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 164180360409c9e4e9163c670ff48663244b4057eafMaurice Lam /** 165180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * Sets the start inset of the divider. This will use the default divider drawable set in the 166180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * theme and inset it {@code inset} pixels to the right (or left in RTL layouts). 167180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * 168180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * @param inset The number of pixels to inset on the "start" side of the list divider. Typically 169180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * this will be either {@code @dimen/suw_items_icon_divider_inset} or 170180360409c9e4e9163c670ff48663244b4057eafMaurice Lam * {@code @dimen/suw_items_text_divider_inset}. 171180360409c9e4e9163c670ff48663244b4057eafMaurice Lam */ 172180360409c9e4e9163c670ff48663244b4057eafMaurice Lam public void setDividerInset(int inset) { 173180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDividerInset = inset; 174180360409c9e4e9163c670ff48663244b4057eafMaurice Lam updateDivider(); 175180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 176180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 177180360409c9e4e9163c670ff48663244b4057eafMaurice Lam public int getDividerInset() { 178180360409c9e4e9163c670ff48663244b4057eafMaurice Lam return mDividerInset; 179180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 180180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 181180360409c9e4e9163c670ff48663244b4057eafMaurice Lam private void updateDivider() { 182180360409c9e4e9163c670ff48663244b4057eafMaurice Lam boolean shouldUpdate = true; 183180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) { 184180360409c9e4e9163c670ff48663244b4057eafMaurice Lam shouldUpdate = isLayoutDirectionResolved(); 185180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 186180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (shouldUpdate) { 187180360409c9e4e9163c670ff48663244b4057eafMaurice Lam if (mDefaultDivider == null) { 188180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDefaultDivider = mDividerDecoration.getDivider(); 189180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 190180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDivider = DrawableLayoutDirectionHelper.createRelativeInsetDrawable(mDefaultDivider, 191180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDividerInset /* start */, 0 /* top */, 0 /* end */, 0 /* bottom */, this); 192180360409c9e4e9163c670ff48663244b4057eafMaurice Lam mDividerDecoration.setDivider(mDivider); 193180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 194180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 195180360409c9e4e9163c670ff48663244b4057eafMaurice Lam 196180360409c9e4e9163c670ff48663244b4057eafMaurice Lam public Drawable getDivider() { 197180360409c9e4e9163c670ff48663244b4057eafMaurice Lam return mDivider; 198180360409c9e4e9163c670ff48663244b4057eafMaurice Lam } 199b01f3ef075d501d1f61e6f61794a5cadd3ff2026Maurice Lam} 200