b5bcbd561f3R1022">1022
+ super.setPadding(0, 0, 0, 0);
+ requestLayout();
+ }
+
+ /*
+ * Overrides an @hide method in View
+ */
+ protected void recomputePadding() {
+ setPadding(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
+ }
+
+ @Override
+ public int getPaddingLeft() {
+ return mPaddingLeft;
+ }
+
+ @Override
+ public int getPaddingTop() {
+ return mPaddingTop;
+ }
+
+ @Override
+ public int getPaddingRight() {
+ return mPaddingRight;
+ }
+
+ @Override
+ public int getPaddingBottom() {
+ return mPaddingBottom;
+ }
+
+ public void setFastScrollEnabled(boolean fastScrollEnabled) {
+ mList.setFastScrollEnabled(fastScrollEnabled);
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public void setFastScrollAlwaysVisible(boolean alwaysVisible) {
+ if (requireSdkVersion(Build.VERSION_CODES.HONEYCOMB)) {
+ mList.setFastScrollAlwaysVisible(alwaysVisible);
+ }
+ }
+
+ /**
+ * @return true if the fast scroller will always show. False on pre-Honeycomb devices.
+ * @see AbsListView#isFastScrollAlwaysVisible()
+ */
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public boolean isFastScrollAlwaysVisible() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ return false;
+ }
+ return mList.isFastScrollAlwaysVisible();
+ }
+
+ public void setScrollBarStyle(int style) {
+ mList.setScrollBarStyle(style);
+ }
+
+ public int getScrollBarStyle() {
+ return mList.getScrollBarStyle();
+ }
+
+ public int getPositionForView(View view) {
+ return mList.getPositionForView(view);
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public void setMultiChoiceModeListener(MultiChoiceModeListener listener) {
+ if (requireSdkVersion(Build.VERSION_CODES.HONEYCOMB)) {
+ mList.setMultiChoiceModeListener(listener);
+ }
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ if (superState != BaseSavedState.EMPTY_STATE) {
+ throw new IllegalStateException("Handling non empty state of parent class is not implemented");
+ }
+ return mList.onSaveInstanceState();
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ super.onRestoreInstanceState(BaseSavedState.EMPTY_STATE);
+ mList.onRestoreInstanceState(state);
+ }
+
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+ @Override
+ public boolean canScrollVertically(int direction) {
+ return mList.canScrollVertically(direction);
+ }
+
+ public void setTranscriptMode (int mode) {
+ mList.setTranscriptMode(mode);
+ }
+
+ public void setBlockLayoutChildren(boolean blockLayoutChildren) {
+ mList.setBlockLayoutChildren(blockLayoutChildren);
+ }
+
+ public void setStackFromBottom(boolean stackFromBottom) {
+ mList.setStackFromBottom(stackFromBottom);
+ }
+
+ public boolean isStackFromBottom() {
+ return mList.isStackFromBottom();
+ }
+}
@@ -0,0 +1,156 @@ |
||
| 1 |
+package com.android.views.stickylistheaders; |
|
| 2 |
+ |
|
| 3 |
+import android.content.Context; |
|
| 4 |
+import android.graphics.Canvas; |
|
| 5 |
+import android.graphics.drawable.Drawable; |
|
| 6 |
+import android.os.Build; |
|
| 7 |
+import android.view.View; |
|
| 8 |
+import android.view.ViewGroup; |
|
| 9 |
+import android.view.ViewParent; |
|
| 10 |
+ |
|
| 11 |
+/** |
|
| 12 |
+ * |
|
| 13 |
+ * the view that wrapps a divider header and a normal list item. The listview sees this as 1 item |
|
| 14 |
+ * |
|
| 15 |
+ * @author Emil Sjölander |
|
| 16 |
+ */ |
|
| 17 |
+public class WrapperView extends ViewGroup {
|
|
| 18 |
+ |
|
| 19 |
+ View mItem; |
|
| 20 |
+ Drawable mDivider; |
|
| 21 |
+ int mDividerHeight; |
|
| 22 |
+ View mHeader; |
|
| 23 |
+ int mItemTop; |
|
| 24 |
+ |
|
| 25 |
+ WrapperView(Context c) {
|
|
| 26 |
+ super(c); |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ public boolean hasHeader() {
|
|
| 30 |
+ return mHeader != null; |
|
| 31 |
+ } |
|
| 32 |
+ |
|
| 33 |
+ public View getItem() {
|
|
| 34 |
+ return mItem; |
|
| 35 |
+ } |
|
| 36 |
+ |
|
| 37 |
+ public View getHeader() {
|
|
| 38 |
+ return mHeader; |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ void update(View item, View header, Drawable divider, int dividerHeight) {
|
|
| 42 |
+ |
|
| 43 |
+ //every wrapperview must have a list item |
|
| 44 |
+ if (item == null) {
|
|
| 45 |
+ throw new NullPointerException("List view item must not be null.");
|
|
| 46 |
+ } |
|
| 47 |
+ |
|
| 48 |
+ //only remove the current item if it is not the same as the new item. this can happen if wrapping a recycled view |
|
| 49 |
+ if (this.mItem != item) {
|
|
| 50 |
+ removeView(this.mItem); |
|
| 51 |
+ this.mItem = item; |
|
| 52 |
+ final ViewParent parent = item.getParent(); |
|
| 53 |
+ if(parent != null && parent != this) {
|
|
| 54 |
+ if(parent instanceof ViewGroup) {
|
|
| 55 |
+ ((ViewGroup) parent).removeView(item); |
|
| 56 |
+ } |
|
| 57 |
+ } |
|
| 58 |
+ addView(item); |
|
| 59 |
+ } |
|
| 60 |
+ |
|
| 61 |
+ //same logik as above but for the header |
|
| 62 |
+ if (this.mHeader != header) {
|
|
| 63 |
+ if (this.mHeader != null) {
|
|
| 64 |
+ removeView(this.mHeader); |
|
| 65 |
+ } |
|
| 66 |
+ this.mHeader = header; |
|
| 67 |
+ if (header != null) {
|
|
| 68 |
+ addView(header); |
|
| 69 |
+ } |
|
| 70 |
+ } |
|
| 71 |
+ |
|
| 72 |
+ if (this.mDivider != divider) {
|
|
| 73 |
+ this.mDivider = divider; |
|
| 74 |
+ this.mDividerHeight = dividerHeight; |
|
| 75 |
+ invalidate(); |
|
| 76 |
+ } |
|
| 77 |
+ } |
|
| 78 |
+ |
|
| 79 |
+ @Override |
|
| 80 |
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
| 81 |
+ int measuredWidth = MeasureSpec.getSize(widthMeasureSpec); |
|
| 82 |
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth, |
|
| 83 |
+ MeasureSpec.EXACTLY); |
|
| 84 |
+ int measuredHeight = 0; |
|
| 85 |
+ |
|
| 86 |
+ //measure header or divider. when there is a header visible it acts as the divider |
|
| 87 |
+ if (mHeader != null) {
|
|
| 88 |
+ LayoutParams params = mHeader.getLayoutParams(); |
|
| 89 |
+ if (params != null && params.height > 0) {
|
|
| 90 |
+ mHeader.measure(childWidthMeasureSpec, |
|
| 91 |
+ MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY)); |
|
| 92 |
+ } else {
|
|
| 93 |
+ mHeader.measure(childWidthMeasureSpec, |
|
| 94 |
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); |
|
| 95 |
+ } |
|
| 96 |
+ measuredHeight += mHeader.getMeasuredHeight(); |
|
| 97 |
+ } else if (mDivider != null&&mItem.getVisibility()!=View.GONE) {
|
|
| 98 |
+ measuredHeight += mDividerHeight; |
|
| 99 |
+ } |
|
| 100 |
+ |
|
| 101 |
+ //measure item |
|
| 102 |
+ LayoutParams params = mItem.getLayoutParams(); |
|
| 103 |
+ //enable hiding listview item,ex. toggle off items in group |
|
| 104 |
+ if(mItem.getVisibility()==View.GONE){
|
|
| 105 |
+ mItem.measure(childWidthMeasureSpec, |
|
| 106 |
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY)); |
|
| 107 |
+ }else if (params != null && params.height >= 0) {
|
|
| 108 |
+ mItem.measure(childWidthMeasureSpec, |
|
| 109 |
+ MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY)); |
|
| 110 |
+ measuredHeight += mItem.getMeasuredHeight(); |
|
| 111 |
+ } else {
|
|
| 112 |
+ mItem.measure(childWidthMeasureSpec, |
|
| 113 |
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); |
|
| 114 |
+ measuredHeight += mItem.getMeasuredHeight(); |
|
| 115 |
+ } |
|
| 116 |
+ |
|
| 117 |
+ |
|
| 118 |
+ setMeasuredDimension(measuredWidth, measuredHeight); |
|
| 119 |
+ } |
|
| 120 |
+ |
|
| 121 |
+ @Override |
|
| 122 |
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
| 123 |
+ |
|
| 124 |
+ l = 0; |
|
| 125 |
+ t = 0; |
|
| 126 |
+ r = getWidth(); |
|
| 127 |
+ b = getHeight(); |
|
| 128 |
+ |
|
| 129 |
+ if (mHeader != null) {
|
|
| 130 |
+ int headerHeight = mHeader.getMeasuredHeight(); |
|
| 131 |
+ mHeader.layout(l, t, r, headerHeight); |
|
| 132 |
+ mItemTop = headerHeight; |
|
| 133 |
+ mItem.layout(l, headerHeight, r, b); |
|
| 134 |
+ } else if (mDivider != null) {
|
|
| 135 |
+ mDivider.setBounds(l, t, r, mDividerHeight); |
|
| 136 |
+ mItemTop = mDividerHeight; |
|
| 137 |
+ mItem.layout(l, mDividerHeight, r, b); |
|
| 138 |
+ } else {
|
|
| 139 |
+ mItemTop = t; |
|
| 140 |
+ mItem.layout(l, t, r, b); |
|
| 141 |
+ } |
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ @Override |
|
| 145 |
+ protected void dispatchDraw(Canvas canvas) {
|
|
| 146 |
+ super.dispatchDraw(canvas); |
|
| 147 |
+ if (mHeader == null && mDivider != null&&mItem.getVisibility()!=View.GONE) {
|
|
| 148 |
+ // Drawable.setBounds() does not seem to work pre-honeycomb. So have |
|
| 149 |
+ // to do this instead |
|
| 150 |
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
|
| 151 |
+ canvas.clipRect(0, 0, getWidth(), mDividerHeight); |
|
| 152 |
+ } |
|
| 153 |
+ mDivider.draw(canvas); |
|
| 154 |
+ } |
|
| 155 |
+ } |
|
| 156 |
+} |
@@ -0,0 +1,196 @@ |
||
| 1 |
+package com.android.views.stickylistheaders; |
|
| 2 |
+ |
|
| 3 |
+import android.content.Context; |
|
| 4 |
+import android.graphics.Canvas; |
|
| 5 |
+import android.graphics.Rect; |
|
| 6 |
+import android.os.Build; |
|
| 7 |
+import android.view.View; |
|
| 8 |
+import android.widget.AbsListView; |
|
| 9 |
+import android.widget.ListView; |
|
| 10 |
+ |
|
| 11 |
+import java.lang.reflect.Field; |
|
| 12 |
+import java.util.ArrayList; |
|
| 13 |
+import java.util.List; |
|
| 14 |
+ |
|
| 15 |
+class WrapperViewList extends ListView {
|
|
| 16 |
+ |
|
| 17 |
+ interface LifeCycleListener {
|
|
| 18 |
+ void onDispatchDrawOccurred(Canvas canvas); |
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ private LifeCycleListener mLifeCycleListener; |
|
| 22 |
+ private List<View> mFooterViews; |
|
| 23 |
+ private int mTopClippingLength; |
|
| 24 |
+ private Rect mSelectorRect = new Rect();// for if reflection fails |
|
| 25 |
+ private Field mSelectorPositionField; |
|
| 26 |
+ private boolean mClippingToPadding = true; |
|
| 27 |
+ private boolean mBlockLayoutChildren = false; |
|
| 28 |
+ |
|
| 29 |
+ public WrapperViewList(Context context) {
|
|
| 30 |
+ super(context); |
|
| 31 |
+ |
|
| 32 |
+ // Use reflection to be able to change the size/position of the list |
|
| 33 |
+ // selector so it does not come under/over the header |
|
| 34 |
+ try {
|
|
| 35 |
+ Field selectorRectField = AbsListView.class.getDeclaredField("mSelectorRect");
|
|
| 36 |
+ selectorRectField.setAccessible(true); |
|
| 37 |
+ mSelectorRect = (Rect) selectorRectField.get(this); |
|
| 38 |
+ |
|
| 39 |
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
|
| 40 |
+ mSelectorPositionField = AbsListView.class.getDeclaredField("mSelectorPosition");
|
|
| 41 |
+ mSelectorPositionField.setAccessible(true); |
|
| 42 |
+ } |
|
| 43 |
+ } catch (NoSuchFieldException e) {
|
|
| 44 |
+ e.printStackTrace(); |
|
| 45 |
+ } catch (IllegalArgumentException e) {
|
|
| 46 |
+ e.printStackTrace(); |
|
| 47 |
+ } catch (IllegalAccessException e) {
|
|
| 48 |
+ e.printStackTrace(); |
|
| 49 |
+ } |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ @Override |
|
| 53 |
+ public boolean performItemClick(View view, int position, long id) {
|
|
| 54 |
+ if (view instanceof WrapperView) {
|
|
| 55 |
+ view = ((WrapperView) view).mItem; |
|
| 56 |
+ } |
|
| 57 |
+ return super.performItemClick(view, position, id); |
|
| 58 |
+ } |
|
| 59 |
+ |
|
| 60 |
+ private void positionSelectorRect() {
|
|
| 61 |
+ if (!mSelectorRect.isEmpty()) {
|
|
| 62 |
+ int selectorPosition = getSelectorPosition(); |
|
| 63 |
+ if (selectorPosition >= 0) {
|
|
| 64 |
+ int firstVisibleItem = getFixedFirstVisibleItem(); |
|
| 65 |
+ View v = getChildAt(selectorPosition - firstVisibleItem); |
|
| 66 |
+ if (v instanceof WrapperView) {
|
|
| 67 |
+ WrapperView wrapper = ((WrapperView) v); |
|
| 68 |
+ mSelectorRect.top = wrapper.getTop() + wrapper.mItemTop; |
|
| 69 |
+ } |
|
| 70 |
+ } |
|
| 71 |
+ } |
|
| 72 |
+ } |
|
| 73 |
+ |
|
| 74 |
+ private int getSelectorPosition() {
|
|
| 75 |
+ if (mSelectorPositionField == null) { // not all supported andorid
|
|
| 76 |
+ // version have this variable |
|
| 77 |
+ for (int i = 0; i < getChildCount(); i++) {
|
|
| 78 |
+ if (getChildAt(i).getBottom() == mSelectorRect.bottom) {
|
|
| 79 |
+ return i + getFixedFirstVisibleItem(); |
|
| 80 |
+ } |
|
| 81 |
+ } |
|
| 82 |
+ } else {
|
|
| 83 |
+ try {
|
|
| 84 |
+ return mSelectorPositionField.getInt(this); |
|
| 85 |
+ } catch (IllegalArgumentException e) {
|
|
| 86 |
+ e.printStackTrace(); |
|
| 87 |
+ } catch (IllegalAccessException e) {
|
|
| 88 |
+ e.printStackTrace(); |
|
| 89 |
+ } |
|
| 90 |
+ } |
|
| 91 |
+ return -1; |
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 94 |
+ @Override |
|
| 95 |
+ protected void dispatchDraw(Canvas canvas) {
|
|
| 96 |
+ positionSelectorRect(); |
|
| 97 |
+ if (mTopClippingLength != 0) {
|
|
| 98 |
+ canvas.save(); |
|
| 99 |
+ Rect clipping = canvas.getClipBounds(); |
|
| 100 |
+ clipping.top = mTopClippingLength; |
|
| 101 |
+ canvas.clipRect(clipping); |
|
| 102 |
+ super.dispatchDraw(canvas); |
|
| 103 |
+ canvas.restore(); |
|
| 104 |
+ } else {
|
|
| 105 |
+ super.dispatchDraw(canvas); |
|
| 106 |
+ } |
|
| 107 |
+ mLifeCycleListener.onDispatchDrawOccurred(canvas); |
|
| 108 |
+ } |
|
| 109 |
+ |
|
| 110 |
+ void setLifeCycleListener(LifeCycleListener lifeCycleListener) {
|
|
| 111 |
+ mLifeCycleListener = lifeCycleListener; |
|
| 112 |
+ } |
|
| 113 |
+ |
|
| 114 |
+ @Override |
|
| 115 |
+ public void addFooterView(View v) {
|
|
| 116 |
+ super.addFooterView(v); |
|
| 117 |
+ addInternalFooterView(v); |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+ @Override |
|
| 121 |
+ public void addFooterView(View v, Object data, boolean isSelectable) {
|
|
| 122 |
+ super.addFooterView(v, data, isSelectable); |
|
| 123 |
+ addInternalFooterView(v); |
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ private void addInternalFooterView(View v) {
|
|
| 127 |
+ if (mFooterViews == null) {
|
|
| 128 |
+ mFooterViews = new ArrayList<View>(); |
|
| 129 |
+ } |
|
| 130 |
+ mFooterViews.add(v); |
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 133 |
+ @Override |
|
| 134 |
+ public boolean removeFooterView(View v) {
|
|
| 135 |
+ if (super.removeFooterView(v)) {
|
|
| 136 |
+ mFooterViews.remove(v); |
|
| 137 |
+ return true; |
|
| 138 |
+ } |
|
| 139 |
+ return false; |
|
| 140 |
+ } |
|
| 141 |
+ |
|
| 142 |
+ boolean containsFooterView(View v) {
|
|
| 143 |
+ if (mFooterViews == null) {
|
|
| 144 |
+ return false; |
|
| 145 |
+ } |
|
| 146 |
+ return mFooterViews.contains(v); |
|
| 147 |
+ } |
|
| 148 |
+ |
|
| 149 |
+ void setTopClippingLength(int topClipping) {
|
|
| 150 |
+ mTopClippingLength = topClipping; |
|
| 151 |
+ } |
|
| 152 |
+ |
|
| 153 |
+ int getFixedFirstVisibleItem() {
|
|
| 154 |
+ int firstVisibleItem = getFirstVisiblePosition(); |
|
| 155 |
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
|
| 156 |
+ return firstVisibleItem; |
|
| 157 |
+ } |
|
| 158 |
+ |
|
| 159 |
+ // first getFirstVisiblePosition() reports items |
|
| 160 |
+ // outside the view sometimes on old versions of android |
|
| 161 |
+ for (int i = 0; i < getChildCount(); i++) {
|
|
| 162 |
+ if (getChildAt(i).getBottom() >= 0) {
|
|
| 163 |
+ firstVisibleItem += i; |
|
| 164 |
+ break; |
|
| 165 |
+ } |
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 168 |
+ // work around to fix bug with firstVisibleItem being to high |
|
| 169 |
+ // because list view does not take clipToPadding=false into account |
|
| 170 |
+ // on old versions of android |
|
| 171 |
+ if (!mClippingToPadding && getPaddingTop() > 0 && firstVisibleItem > 0) {
|
|
| 172 |
+ if (getChildAt(0).getTop() > 0) {
|
|
| 173 |
+ firstVisibleItem -= 1; |
|
| 174 |
+ } |
|
| 175 |
+ } |
|
| 176 |
+ |
|
| 177 |
+ return firstVisibleItem; |
|
| 178 |
+ } |
|
| 179 |
+ |
|
| 180 |
+ @Override |
|
| 181 |
+ public void setClipToPadding(boolean clipToPadding) {
|
|
| 182 |
+ mClippingToPadding = clipToPadding; |
|
| 183 |
+ super.setClipToPadding(clipToPadding); |
|
| 184 |
+ } |
|
| 185 |
+ |
|
| 186 |
+ public void setBlockLayoutChildren(boolean block) {
|
|
| 187 |
+ mBlockLayoutChildren = block; |
|
| 188 |
+ } |
|
| 189 |
+ |
|
| 190 |
+ @Override |
|
| 191 |
+ protected void layoutChildren() {
|
|
| 192 |
+ if (!mBlockLayoutChildren) {
|
|
| 193 |
+ super.layoutChildren(); |
|
| 194 |
+ } |
|
| 195 |
+ } |
|
| 196 |
+} |
@@ -87,4 +87,38 @@ |
||
| 87 | 87 |
</declare-styleable> |
| 88 | 88 |
|
| 89 | 89 |
<attr name="SwipeBackLayoutStyle" format="reference"/> |
| 90 |
+ |
|
| 91 |
+ <declare-styleable name="StickyListHeadersListView"> |
|
| 92 |
+ <attr name="stickyListHeadersListViewStyle" format="reference"/> |
|
| 93 |
+ |
|
| 94 |
+ <!-- View attributes --> |
|
| 95 |
+ <attr name="android:clipToPadding" /> |
|
| 96 |
+ <attr name="android:scrollbars" /> |
|
| 97 |
+ <attr name="android:overScrollMode" /> |
|
| 98 |
+ <attr name="android:padding" /> |
|
| 99 |
+ <attr name="android:paddingLeft" /> |
|
| 100 |
+ <attr name="android:paddingTop" /> |
|
| 101 |
+ <attr name="android:paddingRight" /> |
|
| 102 |
+ <attr name="android:paddingBottom" /> |
|
| 103 |
+ |
|
| 104 |
+ <!-- ListView attributes --> |
|
| 105 |
+ <attr name="android:fadingEdgeLength" /> |
|
| 106 |
+ <attr name="android:requiresFadingEdge" /> |
|
| 107 |
+ <attr name="android:cacheColorHint" /> |
|
| 108 |
+ <attr name="android:choiceMode" /> |
|
| 109 |
+ <attr name="android:drawSelectorOnTop" /> |
|
| 110 |
+ <attr name="android:fastScrollEnabled" /> |
|
| 111 |
+ <attr name="android:fastScrollAlwaysVisible" /> |
|
| 112 |
+ <attr name="android:listSelector" /> |
|
| 113 |
+ <attr name="android:scrollingCache" /> |
|
| 114 |
+ <attr name="android:scrollbarStyle" /> |
|
| 115 |
+ <attr name="android:divider" /> |
|
| 116 |
+ <attr name="android:dividerHeight" /> |
|
| 117 |
+ <attr name="android:transcriptMode" /> |
|
| 118 |
+ <attr name="android:stackFromBottom" /> |
|
| 119 |
+ |
|
| 120 |
+ <!-- StickyListHeaders attributes --> |
|
| 121 |
+ <attr name="hasStickyHeaders" format="boolean" /> |
|
| 122 |
+ <attr name="isDrawingListUnderStickyHeader" format="boolean" /> |
|
| 123 |
+ </declare-styleable> |
|
| 90 | 124 |
</resources> |