aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/StickyListHeaders/library/src/se/emilsjolander/stickylistheaders/WrapperView.java
blob: f51416c1ca2d6c4d60050f3e2f261d719a468a3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package se.emilsjolander.stickylistheaders;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

/**
 * 
 * the view that wrapps a divider header and a normal list item. The listview sees this as 1 item
 * 
 * @author Emil Sjölander
 */
public class WrapperView extends ViewGroup {

	View mItem;
	Drawable mDivider;
	int mDividerHeight;
	View mHeader;
	int mItemTop;

	WrapperView(Context c) {
		super(c);
	}

	public boolean hasHeader() {
		return mHeader != null;
	}
	
	public View getItem() {
		return mItem;
	}
	
	public View getHeader() {
		return mHeader;
	}

	void update(View item, View header, Drawable divider, int dividerHeight) {
		
		//every wrapperview must have a list item
		if (item == null) {
			throw new NullPointerException("List view item must not be null.");
		}

		//only remove the current item if it is not the same as the new item. this can happen if wrapping a recycled view
		if (this.mItem != item) {
			removeView(this.mItem);
			this.mItem = item;
			final ViewParent parent = item.getParent();
			if(parent != null && parent != this) {
				if(parent instanceof ViewGroup) {
					((ViewGroup) parent).removeView(item);
				}
			}
			addView(item);
		}

		//same logik as above but for the header
		if (this.mHeader != header) {
			if (this.mHeader != null) {
				removeView(this.mHeader);
			}
			this.mHeader = header;
			if (header != null) {
				addView(header);
			}
		}

		if (this.mDivider != divider) {
			this.mDivider = divider;
			this.mDividerHeight = dividerHeight;
			invalidate();
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
		int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth,
				MeasureSpec.EXACTLY);
		int measuredHeight = 0;
		
		//measure header or divider. when there is a header visible it acts as the divider
		if (mHeader != null) {
			ViewGroup.LayoutParams params = mHeader.getLayoutParams();
			if (params != null && params.height > 0) {
				mHeader.measure(childWidthMeasureSpec,
						MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY));
			} else {
				mHeader.measure(childWidthMeasureSpec,
						MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
			}
			measuredHeight += mHeader.getMeasuredHeight();
		} else if (mDivider != null) {
			measuredHeight += mDividerHeight;
		}
		
		//measure item
		ViewGroup.LayoutParams params = mItem.getLayoutParams();
		if (params != null && params.height > 0) {
			mItem.measure(childWidthMeasureSpec,
					MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY));
		} else {
			mItem.measure(childWidthMeasureSpec,
					MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
		}
		measuredHeight += mItem.getMeasuredHeight();

		setMeasuredDimension(measuredWidth, measuredHeight);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {

		l = 0;
		t = 0;
		r = getWidth();
		b = getHeight();

		if (mHeader != null) {
			int headerHeight = mHeader.getMeasuredHeight();
			mHeader.layout(l, t, r, headerHeight);
			mItemTop = headerHeight;
			mItem.layout(l, headerHeight, r, b);
		} else if (mDivider != null) {
			mDivider.setBounds(l, t, r, mDividerHeight);
			mItemTop = mDividerHeight;
			mItem.layout(l, mDividerHeight, r, b);
		} else {
			mItemTop = t;
			mItem.layout(l, t, r, b);
		}
	}

	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (mHeader == null && mDivider != null) {
			// Drawable.setBounds() does not seem to work pre-honeycomb. So have
			// to do this instead
			if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
				canvas.clipRect(0, 0, getWidth(), mDividerHeight);
			}
			mDivider.draw(canvas);
		}
	}
}