Skip to content

Commit c98d0e2

Browse files
author
Paul Soucy
committed
Added an IteratorListView and a SimplePrefsStorage
1 parent c54bd61 commit c98d0e2

File tree

2 files changed

+325
-0
lines changed

2 files changed

+325
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.devsmart.android;
2+
3+
import org.json.JSONException;
4+
import org.json.JSONObject;
5+
6+
import android.content.Context;
7+
import android.content.SharedPreferences;
8+
import android.content.SharedPreferences.Editor;
9+
import android.util.Log;
10+
11+
public class SimplePrefsStorage {
12+
13+
public static final String PREFS_NAME = "simpleprefs";
14+
private static final String KEY_NAME = "jsonprefs";
15+
16+
private SharedPreferences mPrefs;
17+
18+
public SimplePrefsStorage(Context context) {
19+
mPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
20+
}
21+
22+
public void clear() {
23+
Editor e = mPrefs.edit();
24+
e.clear();
25+
e.commit();
26+
}
27+
28+
29+
public JSONObject getData() {
30+
JSONObject retval = new JSONObject();
31+
String jsonstr = mPrefs.getString(KEY_NAME, null);
32+
if(jsonstr != null){
33+
try {
34+
retval = new JSONObject(jsonstr);
35+
} catch (JSONException e) {
36+
Log.e(SimplePrefsStorage.class.getName(), "", e);
37+
}
38+
}
39+
return retval;
40+
}
41+
42+
public void save(JSONObject data) {
43+
Editor e = mPrefs.edit();
44+
e.putString(KEY_NAME, data.toString());
45+
e.commit();
46+
}
47+
48+
}
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
package com.devsmart.android.ui;
2+
3+
import java.util.LinkedList;
4+
import java.util.ListIterator;
5+
import java.util.Queue;
6+
7+
import android.content.Context;
8+
import android.util.AttributeSet;
9+
import android.view.GestureDetector;
10+
import android.view.MotionEvent;
11+
import android.view.View;
12+
import android.view.ViewGroup;
13+
import android.widget.Scroller;
14+
15+
public class IteratorListView extends ViewGroup {
16+
17+
public interface ViewAdapter<T extends Object> {
18+
19+
View getView(T obj, View poll, IteratorListView iteratorListView);
20+
21+
}
22+
23+
private Queue<View> mRemovedViewQueue = new LinkedList<View>();
24+
private Scroller mScroller;
25+
private GestureDetector mScrollGestureDetector;
26+
//number of pixes to scroll on the next onLayout
27+
private int mdY = 0;
28+
private int mLastY = 0;
29+
private int mYOffset = 0;
30+
private boolean mIsFingerDown;
31+
private int mTopItem = 0;
32+
private int mBottomItem = 0;
33+
private int mCurrentItem = 0;
34+
private ListIterator<?> mIterator;
35+
private ViewAdapter<Object> mAdapter;
36+
37+
public IteratorListView(Context context) {
38+
super(context);
39+
init();
40+
}
41+
42+
public IteratorListView(Context context, AttributeSet attrs) {
43+
super(context, attrs);
44+
init();
45+
}
46+
47+
private void init() {
48+
mScroller = new Scroller(getContext());
49+
mScrollGestureDetector = new GestureDetector(getContext(), mOnGesture);
50+
}
51+
52+
public <T> void setIteratorAdapter(ListIterator<T> iterator, ViewAdapter<T> adapter) {
53+
mIterator = iterator;
54+
mAdapter = (ViewAdapter<Object>) adapter;
55+
56+
//seek to the top of the list
57+
while(mIterator.hasPrevious()){
58+
mIterator.previous();
59+
}
60+
mTopItem = 0;
61+
mBottomItem = -1;
62+
mCurrentItem = -1;
63+
removeAllViews();
64+
}
65+
66+
private GestureDetector.SimpleOnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {
67+
68+
@Override
69+
public boolean onDown(MotionEvent e) {
70+
mIsFingerDown = true;
71+
mScroller.forceFinished(true);
72+
return true;
73+
}
74+
75+
@Override
76+
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
77+
78+
final int maxScrollDistance = getMeasuredHeight()*1;
79+
mLastY = 0;
80+
mScroller.fling(0, mdY, 0, Math.round(velocityY), 0, 0, -maxScrollDistance, maxScrollDistance);
81+
requestLayout();
82+
return true;
83+
}
84+
85+
@Override
86+
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
87+
mdY -= Math.round(distanceY);
88+
requestLayout();
89+
return true;
90+
91+
}
92+
93+
};
94+
95+
@Override
96+
public boolean onTouchEvent(MotionEvent event) {
97+
boolean retval = mScrollGestureDetector.onTouchEvent(event);
98+
99+
if(event.getAction() == MotionEvent.ACTION_UP){
100+
mIsFingerDown = false;
101+
if(getChildCount() > 0){
102+
int topOfFirstChild = getChildAt(0).getTop();
103+
if(topOfFirstChild + mdY > 0){
104+
mScroller.forceFinished(true);
105+
mLastY = 0;
106+
mScroller.startScroll(0, 0, mdY, -mYOffset);
107+
requestLayout();
108+
}
109+
}
110+
}
111+
112+
return retval;
113+
}
114+
115+
@Override
116+
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
117+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
118+
for(int i = 0;i<getChildCount();i++){
119+
View child = getChildAt(i);
120+
int oldHeight = child.getMeasuredHeight();
121+
child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
122+
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.UNSPECIFIED));
123+
124+
int childDiff = child.getMeasuredHeight() - oldHeight;
125+
if(childDiff > 0 && child.getBottom() < getHeight()/2){
126+
mYOffset -= childDiff;
127+
}
128+
}
129+
}
130+
131+
@Override
132+
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
133+
134+
if(mAdapter == null){
135+
return;
136+
}
137+
138+
if(mScroller.computeScrollOffset()){
139+
int y = mScroller.getCurrY();
140+
mdY += y - mLastY;
141+
mLastY = y;
142+
}
143+
144+
mYOffset += mdY;
145+
146+
removeNonVisibleItems();
147+
fillDown();
148+
fillUp();
149+
positionItems();
150+
151+
mdY = 0;
152+
153+
if(!mScroller.isFinished()){
154+
post(new Runnable(){
155+
@Override
156+
public void run() {
157+
requestLayout();
158+
}
159+
});
160+
161+
} else if(mYOffset > 0 && !mIsFingerDown){
162+
mLastY = 0;
163+
mScroller.startScroll(0, 0, mdY, -mYOffset);
164+
post(new Runnable(){
165+
@Override
166+
public void run() {
167+
requestLayout();
168+
}
169+
});
170+
}
171+
}
172+
173+
private void removeNonVisibleItems(){
174+
175+
176+
final int height = getHeight();
177+
View child = getChildAt(0);
178+
179+
//remove from top
180+
while(child != null && child.getBottom() + mdY < 0){
181+
removeViewInLayout(child);
182+
mRemovedViewQueue.offer(child);
183+
mYOffset += child.getMeasuredHeight();
184+
child = getChildAt(0);
185+
mTopItem++;
186+
}
187+
188+
//remove from bottom
189+
child = getChildAt(getChildCount()-1);
190+
while(child != null && child.getTop() + mdY > height){
191+
removeViewInLayout(child);
192+
mRemovedViewQueue.offer(child);
193+
child = getChildAt(getChildCount()-1);
194+
mBottomItem--;
195+
}
196+
197+
}
198+
199+
private void addAndMeasureChild(View child, int index){
200+
LayoutParams layoutparams = child.getLayoutParams();
201+
if(layoutparams == null){
202+
layoutparams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
203+
}
204+
addViewInLayout(child, index, layoutparams, true);
205+
child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
206+
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.UNSPECIFIED));
207+
}
208+
209+
private View getView(Object obj) {
210+
View child = mAdapter.getView(obj, mRemovedViewQueue.poll(), this);
211+
return child;
212+
}
213+
214+
private void fillDown() {
215+
216+
if(mAdapter == null){
217+
return;
218+
}
219+
220+
final int windowHeight = getHeight();
221+
222+
int bottomOfLastChild = 0;
223+
if(getChildCount() > 0){
224+
bottomOfLastChild = getChildAt(getChildCount()-1).getBottom();
225+
}
226+
227+
while(bottomOfLastChild + mdY < windowHeight && mIterator.hasNext()) {
228+
229+
Object obj = mIterator.next();
230+
mCurrentItem++;
231+
232+
if(mCurrentItem > mBottomItem){
233+
View child = getView(obj);
234+
addAndMeasureChild(child, -1);
235+
bottomOfLastChild += child.getMeasuredHeight();
236+
mBottomItem = mCurrentItem;
237+
}
238+
}
239+
}
240+
241+
private void fillUp() {
242+
243+
if(mAdapter == null){
244+
return;
245+
}
246+
247+
int topOfFirstChild = 0;
248+
if(getChildCount() > 0){
249+
topOfFirstChild = getChildAt(0).getTop();
250+
}
251+
252+
while(topOfFirstChild + mdY > 0 && mIterator.hasPrevious()) {
253+
254+
Object obj = mIterator.previous();
255+
mCurrentItem--;
256+
257+
if(mCurrentItem < mTopItem){
258+
View child = getView(obj);
259+
addAndMeasureChild(child, 0);
260+
topOfFirstChild -= child.getMeasuredHeight();
261+
mYOffset -= child.getMeasuredHeight();
262+
mTopItem = mCurrentItem;
263+
}
264+
}
265+
}
266+
267+
private void positionItems() {
268+
int top = mYOffset;
269+
for(int i=0;i<getChildCount();i++){
270+
View child = getChildAt(i);
271+
int childHeight = child.getMeasuredHeight();
272+
child.layout(0, top, child.getMeasuredWidth(), top + childHeight);
273+
top += childHeight;
274+
}
275+
}
276+
277+
}

0 commit comments

Comments
 (0)