22 | * The onChanged() method is called whenever current wheel positions is changed:
23 | *
New Wheel position is set
24 | *
Wheel view is scrolled
25 | */
26 | public interface OnWheelChangedListener {
27 | /**
28 | * Callback method to be invoked when current item changed
29 | *
30 | * @param wheel
31 | * the wheel view whose state has changed
32 | * @param oldValue
33 | * the old value of current item
34 | * @param newValue
35 | * the new value of current item
36 | */
37 | void onChanged(WheelView wheel, int oldValue, int newValue);
38 | }
39 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/OnWheelClickedListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package kankan.wheel.widget;
18 |
19 | /**
20 | * Wheel clicked listener interface.
21 | *
22 | * The onItemClicked() method is called whenever a wheel item is clicked
23 | *
New Wheel position is set
24 | *
Wheel view is scrolled
25 | */
26 | public interface OnWheelClickedListener {
27 | /**
28 | * Callback method to be invoked when current item clicked
29 | *
30 | * @param wheel
31 | * the wheel view
32 | * @param itemIndex
33 | * the index of clicked item
34 | */
35 | void onItemClicked(WheelView wheel, int itemIndex);
36 | }
37 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/OnWheelScrollListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package kankan.wheel.widget;
18 |
19 | /**
20 | * Wheel scrolled listener interface.
21 | */
22 | public interface OnWheelScrollListener {
23 | /**
24 | * Callback method to be invoked when scrolling started.
25 | *
26 | * @param wheel
27 | * the wheel view whose state has changed.
28 | */
29 | void onScrollingStarted(WheelView wheel);
30 |
31 | /**
32 | * Callback method to be invoked when scrolling ended.
33 | *
34 | * @param wheel
35 | * the wheel view whose state has changed.
36 | */
37 | void onScrollingFinished(WheelView wheel);
38 | }
39 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/WheelAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package kankan.wheel.widget;
18 |
19 | /**
20 | * Wheel adapter interface
21 | *
22 | * @deprecated Use WheelViewAdapter
23 | */
24 | public interface WheelAdapter {
25 | /**
26 | * Gets items count
27 | *
28 | * @return the count of wheel items
29 | */
30 | public int getItemsCount();
31 |
32 | /**
33 | * Gets a wheel item by index.
34 | *
35 | * @param index
36 | * the item index
37 | * @return the wheel item text or null
38 | */
39 | public String getItem(int index);
40 |
41 | /**
42 | * Gets maximum item length. It is used to determine the wheel width. If -1
43 | * is returned there will be used the default wheel width.
44 | *
45 | * @return the maximum item length or -1
46 | */
47 | public int getMaximumLength();
48 | }
49 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/WheelRecycle.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Android Wheel Control.
3 | * https://code.google.com/p/android-wheel/
4 | *
5 | * Copyright 2011 Yuri Kanivets
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | package kankan.wheel.widget;
21 |
22 | import java.util.LinkedList;
23 | import java.util.List;
24 |
25 | import android.view.View;
26 | import android.widget.LinearLayout;
27 |
28 | /**
29 | * Recycle stores wheel items to reuse.
30 | */
31 | public class WheelRecycle {
32 | // Cached items
33 | private List items;
34 |
35 | // Cached empty items
36 | private List emptyItems;
37 |
38 | // Wheel view
39 | private WheelView wheel;
40 |
41 | /**
42 | * Constructor
43 | *
44 | * @param wheel
45 | * the wheel view
46 | */
47 | public WheelRecycle(WheelView wheel) {
48 | this.wheel = wheel;
49 | }
50 |
51 | /**
52 | * Recycles items from specified layout. There are saved only items not
53 | * included to specified range. All the cached items are removed from
54 | * original layout.
55 | *
56 | * @param layout
57 | * the layout containing items to be cached
58 | * @param firstItem
59 | * the number of first item in layout
60 | * @param range
61 | * the range of current wheel items
62 | * @return the new value of first item number
63 | */
64 | public int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) {
65 | int index = firstItem;
66 | for (int i = 0; i < layout.getChildCount();) {
67 | if (!range.contains(index)) {
68 | recycleView(layout.getChildAt(i), index);
69 | layout.removeViewAt(i);
70 | if (i == 0) { // first item
71 | firstItem++;
72 | }
73 | } else {
74 | i++; // go to next item
75 | }
76 | index++;
77 | }
78 | return firstItem;
79 | }
80 |
81 | /**
82 | * Gets item view
83 | *
84 | * @return the cached view
85 | */
86 | public View getItem() {
87 | return getCachedView(items);
88 | }
89 |
90 | /**
91 | * Gets empty item view
92 | *
93 | * @return the cached empty view
94 | */
95 | public View getEmptyItem() {
96 | return getCachedView(emptyItems);
97 | }
98 |
99 | /**
100 | * Clears all views
101 | */
102 | public void clearAll() {
103 | if (items != null) {
104 | items.clear();
105 | }
106 | if (emptyItems != null) {
107 | emptyItems.clear();
108 | }
109 | }
110 |
111 | /**
112 | * Adds view to specified cache. Creates a cache list if it is null.
113 | *
114 | * @param view
115 | * the view to be cached
116 | * @param cache
117 | * the cache list
118 | * @return the cache list
119 | */
120 | private List addView(View view, List cache) {
121 | if (cache == null) {
122 | cache = new LinkedList();
123 | }
124 |
125 | cache.add(view);
126 | return cache;
127 | }
128 |
129 | /**
130 | * Adds view to cache. Determines view type (item view or empty one) by
131 | * index.
132 | *
133 | * @param view
134 | * the view to be cached
135 | * @param index
136 | * the index of view
137 | */
138 | private void recycleView(View view, int index) {
139 | int count = wheel.getViewAdapter().getItemsCount();
140 |
141 | if ((index < 0 || index >= count) && !wheel.isCyclic()) {
142 | // empty view
143 | emptyItems = addView(view, emptyItems);
144 | } else {
145 | while (index < 0) {
146 | index = count + index;
147 | }
148 | index %= count;
149 | items = addView(view, items);
150 | }
151 | }
152 |
153 | /**
154 | * Gets view from specified cache.
155 | *
156 | * @param cache
157 | * the cache
158 | * @return the first view from cache.
159 | */
160 | private View getCachedView(List cache) {
161 | if (cache != null && cache.size() > 0) {
162 | View view = cache.get(0);
163 | cache.remove(0);
164 | return view;
165 | }
166 | return null;
167 | }
168 |
169 | }
170 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/WheelScroller.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Android Wheel Control.
3 | * https://code.google.com/p/android-wheel/
4 | *
5 | * Copyright 2011 Yuri Kanivets
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | package kankan.wheel.widget;
21 |
22 | import android.content.Context;
23 | import android.os.Handler;
24 | import android.os.Message;
25 | import android.view.GestureDetector;
26 | import android.view.GestureDetector.SimpleOnGestureListener;
27 | import android.view.MotionEvent;
28 | import android.view.animation.Interpolator;
29 | import android.widget.Scroller;
30 |
31 | /**
32 | * Scroller class handles scrolling events and updates the
33 | */
34 | public class WheelScroller {
35 | /**
36 | * Scrolling listener interface
37 | */
38 | public interface ScrollingListener {
39 | /**
40 | * Scrolling callback called when scrolling is performed.
41 | *
42 | * @param distance
43 | * the distance to scroll
44 | */
45 | void onScroll(int distance);
46 |
47 | /**
48 | * Starting callback called when scrolling is started
49 | */
50 | void onStarted();
51 |
52 | /**
53 | * Finishing callback called after justifying
54 | */
55 | void onFinished();
56 |
57 | /**
58 | * Justifying callback called to justify a view when scrolling is ended
59 | */
60 | void onJustify();
61 | }
62 |
63 | /** Scrolling duration */
64 | private static final int SCROLLING_DURATION = 400;
65 |
66 | /** Minimum delta for scrolling */
67 | public static final int MIN_DELTA_FOR_SCROLLING = 1;
68 |
69 | // Listener
70 | private ScrollingListener listener;
71 |
72 | // Context
73 | private Context context;
74 |
75 | // Scrolling
76 | private GestureDetector gestureDetector;
77 | private Scroller scroller;
78 | private int lastScrollY;
79 | private float lastTouchedY;
80 | private boolean isScrollingPerformed;
81 |
82 | /**
83 | * Constructor
84 | *
85 | * @param context
86 | * the current context
87 | * @param listener
88 | * the scrolling listener
89 | */
90 | public WheelScroller(Context context, ScrollingListener listener) {
91 | gestureDetector = new GestureDetector(context, gestureListener);
92 | gestureDetector.setIsLongpressEnabled(false);
93 |
94 | scroller = new Scroller(context);
95 |
96 | this.listener = listener;
97 | this.context = context;
98 | }
99 |
100 | /**
101 | * Set the the specified scrolling interpolator
102 | *
103 | * @param interpolator
104 | * the interpolator
105 | */
106 | public void setInterpolator(Interpolator interpolator) {
107 | scroller.forceFinished(true);
108 | scroller = new Scroller(context, interpolator);
109 | }
110 |
111 | /**
112 | * Scroll the wheel
113 | *
114 | * @param distance
115 | * the scrolling distance
116 | * @param time
117 | * the scrolling duration
118 | */
119 | public void scroll(int distance, int time) {
120 | scroller.forceFinished(true);
121 |
122 | lastScrollY = 0;
123 |
124 | scroller.startScroll(0, 0, 0, distance, time != 0 ? time : SCROLLING_DURATION);
125 | setNextMessage(MESSAGE_SCROLL);
126 |
127 | startScrolling();
128 | }
129 |
130 | /**
131 | * Stops scrolling
132 | */
133 | public void stopScrolling() {
134 | scroller.forceFinished(true);
135 | }
136 |
137 | /**
138 | * Handles Touch event
139 | *
140 | * @param event
141 | * the motion event
142 | * @return
143 | */
144 | public boolean onTouchEvent(MotionEvent event) {
145 | switch (event.getAction()) {
146 | case MotionEvent.ACTION_DOWN:
147 | lastTouchedY = event.getY();
148 | scroller.forceFinished(true);
149 | clearMessages();
150 | break;
151 |
152 | case MotionEvent.ACTION_MOVE:
153 | // perform scrolling
154 | int distanceY = (int) (event.getY() - lastTouchedY);
155 | if (distanceY != 0) {
156 | startScrolling();
157 | listener.onScroll(distanceY);
158 | lastTouchedY = event.getY();
159 | }
160 | break;
161 | }
162 |
163 | if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {
164 | justify();
165 | }
166 |
167 | return true;
168 | }
169 |
170 | // gesture listener
171 | private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
172 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
173 | // Do scrolling in onTouchEvent() since onScroll() are not call
174 | // immediately
175 | // when user touch and move the wheel
176 | return true;
177 | }
178 |
179 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
180 | lastScrollY = 0;
181 | final int maxY = 0x7FFFFFFF;
182 | final int minY = -maxY;
183 | scroller.fling(0, lastScrollY, 0, (int) -velocityY, 0, 0, minY, maxY);
184 | setNextMessage(MESSAGE_SCROLL);
185 | return true;
186 | }
187 | };
188 |
189 | // Messages
190 | private final int MESSAGE_SCROLL = 0;
191 | private final int MESSAGE_JUSTIFY = 1;
192 |
193 | /**
194 | * Set next message to queue. Clears queue before.
195 | *
196 | * @param message
197 | * the message to set
198 | */
199 | private void setNextMessage(int message) {
200 | clearMessages();
201 | animationHandler.sendEmptyMessage(message);
202 | }
203 |
204 | /**
205 | * Clears messages from queue
206 | */
207 | private void clearMessages() {
208 | animationHandler.removeMessages(MESSAGE_SCROLL);
209 | animationHandler.removeMessages(MESSAGE_JUSTIFY);
210 | }
211 |
212 | // animation handler
213 | private Handler animationHandler = new Handler() {
214 | public void handleMessage(Message msg) {
215 | scroller.computeScrollOffset();
216 | int currY = scroller.getCurrY();
217 | int delta = lastScrollY - currY;
218 | lastScrollY = currY;
219 | if (delta != 0) {
220 | listener.onScroll(delta);
221 | }
222 |
223 | // scrolling is not finished when it comes to final Y
224 | // so, finish it manually
225 | if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {
226 | currY = scroller.getFinalY();
227 | scroller.forceFinished(true);
228 | }
229 | if (!scroller.isFinished()) {
230 | animationHandler.sendEmptyMessage(msg.what);
231 | } else if (msg.what == MESSAGE_SCROLL) {
232 | justify();
233 | } else {
234 | finishScrolling();
235 | }
236 | }
237 | };
238 |
239 | /**
240 | * Justifies wheel
241 | */
242 | private void justify() {
243 | listener.onJustify();
244 | setNextMessage(MESSAGE_JUSTIFY);
245 | }
246 |
247 | /**
248 | * Starts scrolling
249 | */
250 | private void startScrolling() {
251 | if (!isScrollingPerformed) {
252 | isScrollingPerformed = true;
253 | listener.onStarted();
254 | }
255 | }
256 |
257 | /**
258 | * Finishes scrolling
259 | */
260 | void finishScrolling() {
261 | if (isScrollingPerformed) {
262 | listener.onFinished();
263 | isScrollingPerformed = false;
264 | }
265 | }
266 | }
267 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/WheelView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Android Wheel Control.
3 | * https://code.google.com/p/android-wheel/
4 | *
5 | * Copyright 2011 Yuri Kanivets
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | package kankan.wheel.widget;
21 |
22 | import java.util.LinkedList;
23 | import java.util.List;
24 |
25 | import kankan.wheel.R;
26 | import kankan.wheel.widget.adapters.WheelViewAdapter;
27 |
28 | import android.content.Context;
29 | import android.database.DataSetObserver;
30 | import android.graphics.Canvas;
31 | import android.graphics.drawable.Drawable;
32 | import android.graphics.drawable.GradientDrawable;
33 | import android.graphics.drawable.GradientDrawable.Orientation;
34 | import android.util.AttributeSet;
35 | import android.view.MotionEvent;
36 | import android.view.View;
37 | import android.view.ViewGroup.LayoutParams;
38 | import android.view.animation.Interpolator;
39 | import android.widget.LinearLayout;
40 |
41 | /**
42 | * Numeric wheel view.
43 | *
44 | * @author Yuri Kanivets
45 | */
46 | public class WheelView extends View {
47 |
48 | /** Top and bottom shadows colors */
49 | private static int[] SHADOWS_COLORS = new int[] { 0xFF111111,
50 | 0x00AAAAAA, 0x00AAAAAA };
51 |
52 | /** Top and bottom items offset (to hide that) */
53 | private static final int ITEM_OFFSET_PERCENT = 10;
54 |
55 | /** Left and right padding value */
56 | private static final int PADDING = 10;
57 |
58 | /** Default count of visible items */
59 | private static final int DEF_VISIBLE_ITEMS = 5;
60 |
61 | // Wheel Values
62 | private int currentItem = 0;
63 |
64 | // Count of visible items
65 | private int visibleItems = DEF_VISIBLE_ITEMS;
66 |
67 | // Item height
68 | private int itemHeight = 0;
69 |
70 | // Center Line
71 | private Drawable centerDrawable;
72 |
73 | // Wheel drawables
74 | private int wheelBackground = R.drawable.wheel_bg;
75 | private int wheelForeground = R.drawable.wheel_val;
76 |
77 | // Shadows drawables
78 | private GradientDrawable topShadow;
79 | private GradientDrawable bottomShadow;
80 |
81 | // Scrolling
82 | private WheelScroller scroller;
83 | private boolean isScrollingPerformed;
84 | private int scrollingOffset;
85 |
86 | // Cyclic
87 | boolean isCyclic = false;
88 |
89 | // Items layout
90 | private LinearLayout itemsLayout;
91 |
92 | // The number of first item in layout
93 | private int firstItem;
94 |
95 | // View adapter
96 | private WheelViewAdapter viewAdapter;
97 |
98 | // Recycle
99 | private WheelRecycle recycle = new WheelRecycle(this);
100 |
101 | // Listeners
102 | private List changingListeners = new LinkedList();
103 | private List scrollingListeners = new LinkedList();
104 | private List clickingListeners = new LinkedList();
105 |
106 | /**
107 | * Constructor
108 | */
109 | public WheelView(Context context, AttributeSet attrs, int defStyle) {
110 | super(context, attrs, defStyle);
111 | initData(context);
112 | }
113 |
114 | /**
115 | * Constructor
116 | */
117 | public WheelView(Context context, AttributeSet attrs) {
118 | super(context, attrs);
119 | initData(context);
120 | }
121 |
122 | /**
123 | * Constructor
124 | */
125 | public WheelView(Context context) {
126 | super(context);
127 | initData(context);
128 | }
129 |
130 | /**
131 | * Initializes class data
132 | *
133 | * @param context
134 | * the context
135 | */
136 | private void initData(Context context) {
137 | scroller = new WheelScroller(getContext(), scrollingListener);
138 | }
139 |
140 | // Scrolling listener
141 | WheelScroller.ScrollingListener scrollingListener = new WheelScroller.ScrollingListener() {
142 | @Override
143 | public void onStarted() {
144 | isScrollingPerformed = true;
145 | notifyScrollingListenersAboutStart();
146 | }
147 |
148 | @Override
149 | public void onScroll(int distance) {
150 | doScroll(distance);
151 |
152 | int height = getHeight();
153 | if (scrollingOffset > height) {
154 | scrollingOffset = height;
155 | scroller.stopScrolling();
156 | } else if (scrollingOffset < -height) {
157 | scrollingOffset = -height;
158 | scroller.stopScrolling();
159 | }
160 | }
161 |
162 | @Override
163 | public void onFinished() {
164 | if (isScrollingPerformed) {
165 | notifyScrollingListenersAboutEnd();
166 | isScrollingPerformed = false;
167 | }
168 |
169 | scrollingOffset = 0;
170 | invalidate();
171 | }
172 |
173 | @Override
174 | public void onJustify() {
175 | if (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) {
176 | scroller.scroll(scrollingOffset, 0);
177 | }
178 | }
179 | };
180 |
181 | /**
182 | * Set the the specified scrolling interpolator
183 | *
184 | * @param interpolator
185 | * the interpolator
186 | */
187 | public void setInterpolator(Interpolator interpolator) {
188 | scroller.setInterpolator(interpolator);
189 | }
190 |
191 | /**
192 | * Gets count of visible items
193 | *
194 | * @return the count of visible items
195 | */
196 | public int getVisibleItems() {
197 | return visibleItems;
198 | }
199 |
200 | /**
201 | * Sets the desired count of visible items. Actual amount of visible items
202 | * depends on wheel layout parameters. To apply changes and rebuild view
203 | * call measure().
204 | *
205 | * @param count
206 | * the desired count for visible items
207 | */
208 | public void setVisibleItems(int count) {
209 | visibleItems = count;
210 | }
211 |
212 | /**
213 | * Gets view adapter
214 | *
215 | * @return the view adapter
216 | */
217 | public WheelViewAdapter getViewAdapter() {
218 | return viewAdapter;
219 | }
220 |
221 | // Adapter listener
222 | private DataSetObserver dataObserver = new DataSetObserver() {
223 | @Override
224 | public void onChanged() {
225 | invalidateWheel(false);
226 | }
227 |
228 | @Override
229 | public void onInvalidated() {
230 | invalidateWheel(true);
231 | }
232 | };
233 |
234 | /**
235 | * Sets view adapter. Usually new adapters contain different views, so it
236 | * needs to rebuild view by calling measure().
237 | *
238 | * @param viewAdapter
239 | * the view adapter
240 | */
241 | public void setViewAdapter(WheelViewAdapter viewAdapter) {
242 | if (this.viewAdapter != null) {
243 | this.viewAdapter.unregisterDataSetObserver(dataObserver);
244 | }
245 | this.viewAdapter = viewAdapter;
246 | if (this.viewAdapter != null) {
247 | this.viewAdapter.registerDataSetObserver(dataObserver);
248 | }
249 |
250 | invalidateWheel(true);
251 | }
252 |
253 | /**
254 | * Adds wheel changing listener
255 | *
256 | * @param listener
257 | * the listener
258 | */
259 | public void addChangingListener(OnWheelChangedListener listener) {
260 | changingListeners.add(listener);
261 | }
262 |
263 | /**
264 | * Removes wheel changing listener
265 | *
266 | * @param listener
267 | * the listener
268 | */
269 | public void removeChangingListener(OnWheelChangedListener listener) {
270 | changingListeners.remove(listener);
271 | }
272 |
273 | /**
274 | * Notifies changing listeners
275 | *
276 | * @param oldValue
277 | * the old wheel value
278 | * @param newValue
279 | * the new wheel value
280 | */
281 | protected void notifyChangingListeners(int oldValue, int newValue) {
282 | for (OnWheelChangedListener listener : changingListeners) {
283 | listener.onChanged(this, oldValue, newValue);
284 | }
285 | }
286 |
287 | /**
288 | * Adds wheel scrolling listener
289 | *
290 | * @param listener
291 | * the listener
292 | */
293 | public void addScrollingListener(OnWheelScrollListener listener) {
294 | scrollingListeners.add(listener);
295 | }
296 |
297 | /**
298 | * Removes wheel scrolling listener
299 | *
300 | * @param listener
301 | * the listener
302 | */
303 | public void removeScrollingListener(OnWheelScrollListener listener) {
304 | scrollingListeners.remove(listener);
305 | }
306 |
307 | /**
308 | * Notifies listeners about starting scrolling
309 | */
310 | protected void notifyScrollingListenersAboutStart() {
311 | for (OnWheelScrollListener listener : scrollingListeners) {
312 | listener.onScrollingStarted(this);
313 | }
314 | }
315 |
316 | /**
317 | * Notifies listeners about ending scrolling
318 | */
319 | protected void notifyScrollingListenersAboutEnd() {
320 | for (OnWheelScrollListener listener : scrollingListeners) {
321 | listener.onScrollingFinished(this);
322 | }
323 | }
324 |
325 | /**
326 | * Adds wheel clicking listener
327 | *
328 | * @param listener
329 | * the listener
330 | */
331 | public void addClickingListener(OnWheelClickedListener listener) {
332 | clickingListeners.add(listener);
333 | }
334 |
335 | /**
336 | * Removes wheel clicking listener
337 | *
338 | * @param listener
339 | * the listener
340 | */
341 | public void removeClickingListener(OnWheelClickedListener listener) {
342 | clickingListeners.remove(listener);
343 | }
344 |
345 | /**
346 | * Notifies listeners about clicking
347 | */
348 | protected void notifyClickListenersAboutClick(int item) {
349 | for (OnWheelClickedListener listener : clickingListeners) {
350 | listener.onItemClicked(this, item);
351 | }
352 | }
353 |
354 | /**
355 | * Gets current value
356 | *
357 | * @return the current value
358 | */
359 | public int getCurrentItem() {
360 | return currentItem;
361 | }
362 |
363 | /**
364 | * Sets the current item. Does nothing when index is wrong.
365 | *
366 | * @param index
367 | * the item index
368 | * @param animated
369 | * the animation flag
370 | */
371 | public void setCurrentItem(int index, boolean animated) {
372 | if (viewAdapter == null || viewAdapter.getItemsCount() == 0) {
373 | return; // throw?
374 | }
375 |
376 | int itemCount = viewAdapter.getItemsCount();
377 | if (index < 0 || index >= itemCount) {
378 | if (isCyclic) {
379 | while (index < 0) {
380 | index += itemCount;
381 | }
382 | index %= itemCount;
383 | } else {
384 | return; // throw?
385 | }
386 | }
387 | if (index != currentItem) {
388 | if (animated) {
389 | int itemsToScroll = index - currentItem;
390 | if (isCyclic) {
391 | int scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem);
392 | if (scroll < Math.abs(itemsToScroll)) {
393 | itemsToScroll = itemsToScroll < 0 ? scroll : -scroll;
394 | }
395 | }
396 | scroll(itemsToScroll, 0);
397 | } else {
398 | scrollingOffset = 0;
399 |
400 | int old = currentItem;
401 | currentItem = index;
402 |
403 | notifyChangingListeners(old, currentItem);
404 |
405 | invalidate();
406 | }
407 | }
408 | }
409 |
410 | /**
411 | * Sets the current item w/o animation. Does nothing when index is wrong.
412 | *
413 | * @param index
414 | * the item index
415 | */
416 | public void setCurrentItem(int index) {
417 | setCurrentItem(index, false);
418 | }
419 |
420 | /**
421 | * Tests if wheel is cyclic. That means before the 1st item there is shown
422 | * the last one
423 | *
424 | * @return true if wheel is cyclic
425 | */
426 | public boolean isCyclic() {
427 | return isCyclic;
428 | }
429 |
430 | /**
431 | * Set wheel cyclic flag
432 | *
433 | * @param isCyclic
434 | * the flag to set
435 | */
436 | public void setCyclic(boolean isCyclic) {
437 | this.isCyclic = isCyclic;
438 | invalidateWheel(false);
439 | }
440 |
441 | /**
442 | * Set the shadow gradient color
443 | * @param start
444 | * @param middle
445 | * @param end
446 | */
447 | public void setShadowColor(int start, int middle, int end) {
448 | SHADOWS_COLORS = new int[] {start, middle, end};
449 | }
450 |
451 | /**
452 | * Sets the drawable for the wheel background
453 | * @param resource
454 | */
455 | public void setWheelBackground(int resource) {
456 | wheelBackground = resource;
457 | setBackgroundResource(wheelBackground);
458 | }
459 |
460 | /**
461 | * Sets the drawable for the wheel foreground
462 | * @param resource
463 | */
464 | public void setWheelForeground(int resource) {
465 | wheelForeground = resource;
466 | centerDrawable = getContext().getResources().getDrawable(wheelForeground);
467 | }
468 |
469 | /**
470 | * Invalidates wheel
471 | *
472 | * @param clearCaches
473 | * if true then cached views will be clear
474 | */
475 | public void invalidateWheel(boolean clearCaches) {
476 | if (clearCaches) {
477 | recycle.clearAll();
478 | if (itemsLayout != null) {
479 | itemsLayout.removeAllViews();
480 | }
481 | scrollingOffset = 0;
482 | } else if (itemsLayout != null) {
483 | // cache all items
484 | recycle.recycleItems(itemsLayout, firstItem, new ItemsRange());
485 | }
486 |
487 | invalidate();
488 | }
489 |
490 | public LinearLayout getItemLayout(){
491 | return itemsLayout;
492 | }
493 |
494 | /**
495 | * Initializes resources
496 | */
497 | private void initResourcesIfNecessary() {
498 | if (centerDrawable == null) {
499 | centerDrawable = getContext().getResources().getDrawable(wheelForeground);
500 | }
501 |
502 | if (topShadow == null) {
503 | topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);
504 | }
505 |
506 | if (bottomShadow == null) {
507 | bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);
508 | }
509 |
510 | setBackgroundResource(wheelBackground);
511 | }
512 |
513 | /**
514 | * Calculates desired height for layout
515 | *
516 | * @param layout
517 | * the source layout
518 | * @return the desired layout height
519 | */
520 | private int getDesiredHeight(LinearLayout layout) {
521 | if (layout != null && layout.getChildAt(0) != null) {
522 | itemHeight = layout.getChildAt(0).getMeasuredHeight();
523 | }
524 |
525 | int desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50;
526 |
527 | return Math.max(desired, getSuggestedMinimumHeight());
528 | }
529 |
530 | /**
531 | * Returns height of wheel item
532 | *
533 | * @return the item height
534 | */
535 | private int getItemHeight() {
536 | if (itemHeight != 0) {
537 | return itemHeight;
538 | }
539 |
540 | if (itemsLayout != null && itemsLayout.getChildAt(0) != null) {
541 | itemHeight = itemsLayout.getChildAt(0).getHeight();
542 | return itemHeight;
543 | }
544 |
545 | return getHeight() / visibleItems;
546 | }
547 |
548 | /**
549 | * Calculates control width and creates text layouts
550 | *
551 | * @param widthSize
552 | * the input layout width
553 | * @param mode
554 | * the layout mode
555 | * @return the calculated control width
556 | */
557 | private int calculateLayoutWidth(int widthSize, int mode) {
558 | initResourcesIfNecessary();
559 |
560 | // TODO: make it static
561 | itemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
562 | itemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED),
563 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
564 | int width = itemsLayout.getMeasuredWidth();
565 |
566 | if (mode == MeasureSpec.EXACTLY) {
567 | width = widthSize;
568 | } else {
569 | width += 2 * PADDING;
570 |
571 | // Check against our minimum width
572 | width = Math.max(width, getSuggestedMinimumWidth());
573 |
574 | if (mode == MeasureSpec.AT_MOST && widthSize < width) {
575 | width = widthSize;
576 | }
577 | }
578 |
579 | itemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY),
580 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
581 |
582 | return width;
583 | }
584 |
585 | @Override
586 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
587 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
588 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
589 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
590 | int heightSize = MeasureSpec.getSize(heightMeasureSpec);
591 |
592 | buildViewForMeasuring();
593 |
594 | int width = calculateLayoutWidth(widthSize, widthMode);
595 |
596 | int height;
597 | if (heightMode == MeasureSpec.EXACTLY) {
598 | height = heightSize;
599 | } else {
600 | height = getDesiredHeight(itemsLayout);
601 |
602 | if (heightMode == MeasureSpec.AT_MOST) {
603 | height = Math.min(height, heightSize);
604 | }
605 | }
606 |
607 | setMeasuredDimension(width, height);
608 | }
609 |
610 | @Override
611 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
612 | layout(r - l, b - t);
613 | }
614 |
615 | /**
616 | * Sets layouts width and height
617 | *
618 | * @param width
619 | * the layout width
620 | * @param height
621 | * the layout height
622 | */
623 | private void layout(int width, int height) {
624 | int itemsWidth = width - 2 * PADDING;
625 |
626 | itemsLayout.layout(0, 0, itemsWidth, height);
627 | }
628 |
629 | @Override
630 | protected void onDraw(Canvas canvas) {
631 | super.onDraw(canvas);
632 |
633 | if (viewAdapter != null && viewAdapter.getItemsCount() > 0) {
634 | updateView();
635 |
636 | drawItems(canvas);
637 | drawCenterRect(canvas);
638 | }
639 |
640 | drawShadows(canvas);
641 | }
642 |
643 | /**
644 | * Draws shadows on top and bottom of control
645 | *
646 | * @param canvas
647 | * the canvas for drawing
648 | */
649 | private void drawShadows(Canvas canvas) {
650 | int height = (int) (1.5 * getItemHeight());
651 | topShadow.setBounds(0, 0, getWidth(), height);
652 | topShadow.draw(canvas);
653 |
654 | bottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());
655 | bottomShadow.draw(canvas);
656 | }
657 |
658 | /**
659 | * Draws items
660 | *
661 | * @param canvas
662 | * the canvas for drawing
663 | */
664 | private void drawItems(Canvas canvas) {
665 | canvas.save();
666 |
667 | int top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2;
668 | canvas.translate(PADDING, -top + scrollingOffset);
669 |
670 | itemsLayout.draw(canvas);
671 |
672 | canvas.restore();
673 | }
674 |
675 | /**
676 | * Draws rect for current value
677 | *
678 | * @param canvas
679 | * the canvas for drawing
680 | */
681 | private void drawCenterRect(Canvas canvas) {
682 | int center = getHeight() / 2;
683 | int offset = (int) (getItemHeight() / 2 * 1.2);
684 | centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);
685 | centerDrawable.draw(canvas);
686 | }
687 |
688 | @Override
689 | public boolean onTouchEvent(MotionEvent event) {
690 | if (!isEnabled() || getViewAdapter() == null) {
691 | return true;
692 | }
693 |
694 | switch (event.getAction()) {
695 | case MotionEvent.ACTION_MOVE:
696 | if (getParent() != null) {
697 | getParent().requestDisallowInterceptTouchEvent(true);
698 | }
699 | break;
700 |
701 | case MotionEvent.ACTION_UP:
702 | if (!isScrollingPerformed) {
703 | int distance = (int) event.getY() - getHeight() / 2;
704 | if (distance > 0) {
705 | distance += getItemHeight() / 2;
706 | } else {
707 | distance -= getItemHeight() / 2;
708 | }
709 | int items = distance / getItemHeight();
710 | if (items != 0 && isValidItemIndex(currentItem + items)) {
711 | notifyClickListenersAboutClick(currentItem + items);
712 | }
713 | }
714 | break;
715 | }
716 |
717 | return scroller.onTouchEvent(event);
718 | }
719 |
720 | /**
721 | * Scrolls the wheel
722 | *
723 | * @param delta
724 | * the scrolling value
725 | */
726 | private void doScroll(int delta) {
727 | scrollingOffset += delta;
728 |
729 | int itemHeight = getItemHeight();
730 | int count = scrollingOffset / itemHeight;
731 |
732 | int pos = currentItem - count;
733 | int itemCount = viewAdapter.getItemsCount();
734 |
735 | int fixPos = scrollingOffset % itemHeight;
736 | if (Math.abs(fixPos) <= itemHeight / 2) {
737 | fixPos = 0;
738 | }
739 | if (isCyclic && itemCount > 0) {
740 | if (fixPos > 0) {
741 | pos--;
742 | count++;
743 | } else if (fixPos < 0) {
744 | pos++;
745 | count--;
746 | }
747 | // fix position by rotating
748 | while (pos < 0) {
749 | pos += itemCount;
750 | }
751 | pos %= itemCount;
752 | } else {
753 | //
754 | if (pos < 0) {
755 | count = currentItem;
756 | pos = 0;
757 | } else if (pos >= itemCount) {
758 | count = currentItem - itemCount + 1;
759 | pos = itemCount - 1;
760 | } else if (pos > 0 && fixPos > 0) {
761 | pos--;
762 | count++;
763 | } else if (pos < itemCount - 1 && fixPos < 0) {
764 | pos++;
765 | count--;
766 | }
767 | }
768 |
769 | int offset = scrollingOffset;
770 | if (pos != currentItem) {
771 | setCurrentItem(pos, false);
772 | } else {
773 | invalidate();
774 | }
775 |
776 | // update offset
777 | scrollingOffset = offset - count * itemHeight;
778 | if (scrollingOffset > getHeight()) {
779 | scrollingOffset = scrollingOffset % getHeight() + getHeight();
780 | }
781 | }
782 |
783 | /**
784 | * Scroll the wheel
785 | *
786 | * @param itemsToSkip
787 | * items to scroll
788 | * @param time
789 | * scrolling duration
790 | */
791 | public void scroll(int itemsToScroll, int time) {
792 | int distance = itemsToScroll * getItemHeight() - scrollingOffset;
793 | scroller.scroll(distance, time);
794 | }
795 |
796 | /**
797 | * Calculates range for wheel items
798 | *
799 | * @return the items range
800 | */
801 | private ItemsRange getItemsRange() {
802 | if (getItemHeight() == 0) {
803 | return null;
804 | }
805 |
806 | int first = currentItem;
807 | int count = 1;
808 |
809 | while (count * getItemHeight() < getHeight()) {
810 | first--;
811 | count += 2; // top + bottom items
812 | }
813 |
814 | if (scrollingOffset != 0) {
815 | if (scrollingOffset > 0) {
816 | first--;
817 | }
818 | count++;
819 |
820 | // process empty items above the first or below the second
821 | int emptyItems = scrollingOffset / getItemHeight();
822 | first -= emptyItems;
823 | count += Math.asin(emptyItems);
824 | }
825 | return new ItemsRange(first, count);
826 | }
827 |
828 | /**
829 | * Rebuilds wheel items if necessary. Caches all unused items.
830 | *
831 | * @return true if items are rebuilt
832 | */
833 | private boolean rebuildItems() {
834 | boolean updated = false;
835 | ItemsRange range = getItemsRange();
836 | if (itemsLayout != null) {
837 | int first = recycle.recycleItems(itemsLayout, firstItem, range);
838 | updated = firstItem != first;
839 | firstItem = first;
840 | } else {
841 | createItemsLayout();
842 | updated = true;
843 | }
844 |
845 | if (!updated) {
846 | updated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount();
847 | }
848 |
849 | if (firstItem > range.getFirst() && firstItem <= range.getLast()) {
850 | for (int i = firstItem - 1; i >= range.getFirst(); i--) {
851 | if (!addViewItem(i, true)) {
852 | break;
853 | }
854 | firstItem = i;
855 | }
856 | } else {
857 | firstItem = range.getFirst();
858 | }
859 |
860 | int first = firstItem;
861 | for (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) {
862 | if (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) {
863 | first++;
864 | }
865 | }
866 | firstItem = first;
867 |
868 | return updated;
869 | }
870 |
871 | /**
872 | * Updates view. Rebuilds items and label if necessary, recalculate items
873 | * sizes.
874 | */
875 | private void updateView() {
876 | if (rebuildItems()) {
877 | calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);
878 | layout(getWidth(), getHeight());
879 | }
880 | }
881 |
882 | /**
883 | * Creates item layouts if necessary
884 | */
885 | private void createItemsLayout() {
886 | if (itemsLayout == null) {
887 | itemsLayout = new LinearLayout(getContext());
888 | itemsLayout.setOrientation(LinearLayout.VERTICAL);
889 | }
890 | }
891 |
892 | /**
893 | * Builds view for measuring
894 | */
895 | private void buildViewForMeasuring() {
896 | // clear all items
897 | if (itemsLayout != null) {
898 | recycle.recycleItems(itemsLayout, firstItem, new ItemsRange());
899 | } else {
900 | createItemsLayout();
901 | }
902 |
903 | // add views
904 | int addItems = visibleItems / 2;
905 | for (int i = currentItem + addItems; i >= currentItem - addItems; i--) {
906 | if (addViewItem(i, true)) {
907 | firstItem = i;
908 | }
909 | }
910 | }
911 |
912 | /**
913 | * Adds view for item to items layout
914 | *
915 | * @param index
916 | * the item index
917 | * @param first
918 | * the flag indicates if view should be first
919 | * @return true if corresponding item exists and is added
920 | */
921 | private boolean addViewItem(int index, boolean first) {
922 | View view = getItemView(index);
923 | if (view != null) {
924 | if (first) {
925 | itemsLayout.addView(view, 0);
926 | } else {
927 | itemsLayout.addView(view);
928 | }
929 |
930 | return true;
931 | }
932 |
933 | return false;
934 | }
935 |
936 | /**
937 | * Checks whether intem index is valid
938 | *
939 | * @param index
940 | * the item index
941 | * @return true if item index is not out of bounds or the wheel is cyclic
942 | */
943 | private boolean isValidItemIndex(int index) {
944 | return viewAdapter != null && viewAdapter.getItemsCount() > 0
945 | && (isCyclic || index >= 0 && index < viewAdapter.getItemsCount());
946 | }
947 |
948 | /**
949 | * Returns view for specified item
950 | *
951 | * @param index
952 | * the item index
953 | * @return item view or empty view if index is out of bounds
954 | */
955 | private View getItemView(int index) {
956 | if (viewAdapter == null || viewAdapter.getItemsCount() == 0) {
957 | return null;
958 | }
959 | int count = viewAdapter.getItemsCount();
960 | if (!isValidItemIndex(index)) {
961 | return viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout);
962 | } else {
963 | while (index < 0) {
964 | index = count + index;
965 | }
966 | }
967 |
968 | index %= count;
969 | return viewAdapter.getItem(index, recycle.getItem(), itemsLayout);
970 | }
971 |
972 | /**
973 | * Stops scrolling
974 | */
975 | public void stopScrolling() {
976 | scroller.stopScrolling();
977 | }
978 | }
979 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/adapters/AbstractWheelAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package kankan.wheel.widget.adapters;
18 |
19 | import java.util.LinkedList;
20 | import java.util.List;
21 |
22 | import android.database.DataSetObserver;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 |
26 | /**
27 | * Abstract Wheel adapter.
28 | */
29 | public abstract class AbstractWheelAdapter implements WheelViewAdapter {
30 | // Observers
31 | private List datasetObservers;
32 |
33 | @Override
34 | public View getEmptyItem(View convertView, ViewGroup parent) {
35 | return null;
36 | }
37 |
38 | @Override
39 | public void registerDataSetObserver(DataSetObserver observer) {
40 | if (datasetObservers == null) {
41 | datasetObservers = new LinkedList();
42 | }
43 | datasetObservers.add(observer);
44 | }
45 |
46 | @Override
47 | public void unregisterDataSetObserver(DataSetObserver observer) {
48 | if (datasetObservers != null) {
49 | datasetObservers.remove(observer);
50 | }
51 | }
52 |
53 | /**
54 | * Notifies observers about data changing
55 | */
56 | protected void notifyDataChangedEvent() {
57 | if (datasetObservers != null) {
58 | for (DataSetObserver observer : datasetObservers) {
59 | observer.onChanged();
60 | }
61 | }
62 | }
63 |
64 | /**
65 | * Notifies observers about invalidating data
66 | */
67 | protected void notifyDataInvalidatedEvent() {
68 | if (datasetObservers != null) {
69 | for (DataSetObserver observer : datasetObservers) {
70 | observer.onInvalidated();
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/adapters/AbstractWheelTextAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package kankan.wheel.widget.adapters;
17 |
18 | import java.util.ArrayList;
19 |
20 | import android.content.Context;
21 | import android.graphics.Typeface;
22 | import android.util.Log;
23 | import android.view.Gravity;
24 | import android.view.LayoutInflater;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.widget.TextView;
28 |
29 | /**
30 | * Abstract wheel adapter provides common functionality for adapters.
31 | */
32 | public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {
33 |
34 | /** Text view resource. Used as a default view for adapter. */
35 | public static final int TEXT_VIEW_ITEM_RESOURCE = -1;
36 |
37 | /** No resource constant. */
38 | protected static final int NO_RESOURCE = 0;
39 |
40 | /** Default text color */
41 | public static final int DEFAULT_TEXT_COLOR = 0xFF101010;
42 |
43 | /** Default text color */
44 | public static final int LABEL_COLOR = 0xFF700070;
45 |
46 | /** Default text size */
47 | public static final int DEFAULT_TEXT_SIZE = 24;
48 |
49 | // Text settings
50 | private int textColor = DEFAULT_TEXT_COLOR;
51 | private int textSize = DEFAULT_TEXT_SIZE;
52 |
53 | // Current context
54 | protected Context context;
55 | // Layout inflater
56 | protected LayoutInflater inflater;
57 |
58 | // Items resources
59 | protected int itemResourceId;
60 | protected int itemTextResourceId;
61 |
62 | // Empty items resources
63 | protected int emptyItemResourceId;
64 |
65 | private int currentIndex = 0;
66 | private static int maxsize = 24;
67 | private static int minsize = 14;
68 | private ArrayList arrayList = new ArrayList();
69 |
70 | private int selColor;
71 | private int unSelColor;
72 |
73 | /**
74 | * Constructor
75 | *
76 | * @param context
77 | * the current context
78 | */
79 | protected AbstractWheelTextAdapter(Context context) {
80 | this(context, TEXT_VIEW_ITEM_RESOURCE);
81 | }
82 |
83 | /**
84 | * Constructor
85 | *
86 | * @param context
87 | * the current context
88 | * @param itemResource
89 | * the resource ID for a layout file containing a TextView to use
90 | * when instantiating items views
91 | */
92 | protected AbstractWheelTextAdapter(Context context, int itemResource) {
93 | this(context, itemResource, NO_RESOURCE, 0, maxsize, minsize);
94 | }
95 |
96 | protected AbstractWheelTextAdapter(Context context, int itemResource, int maxsize, int minsize) {
97 | this(context, itemResource, NO_RESOURCE, 0, maxsize, minsize);
98 | }
99 |
100 | /**
101 | * Constructor
102 | *
103 | * @param context
104 | * the current context
105 | * @param itemResource
106 | * the resource ID for a layout file containing a TextView to use
107 | * when instantiating items views
108 | * @param itemTextResource
109 | * the resource ID for a text view in the item layout
110 | */
111 | protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource, int currentIndex,
112 | int maxsize, int minsize) {
113 | this.context = context;
114 | itemResourceId = itemResource;
115 | itemTextResourceId = itemTextResource;
116 | this.currentIndex = currentIndex;
117 | this.maxsize = maxsize;
118 | this.minsize = minsize;
119 |
120 | inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
121 | }
122 |
123 | protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource, int currentIndex,
124 | int maxsize, int minsize, int selColor, int unSelColor) {
125 |
126 | // this(context, itemResource, NO_RESOURCE, 0, maxsize, minsize);
127 | this.unSelColor = unSelColor;
128 | this.selColor = selColor;
129 | this.context = context;
130 | itemResourceId = itemResource;
131 | itemTextResourceId = itemTextResource;
132 | this.currentIndex = currentIndex;
133 | this.maxsize = maxsize;
134 | this.minsize = minsize;
135 |
136 | inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
137 | }
138 |
139 | /**
140 | * get the list of show textview
141 | *
142 | * @return the array of textview
143 | */
144 | public ArrayList getTestViews() {
145 | return arrayList;
146 | }
147 |
148 | /**
149 | * Gets text color
150 | *
151 | * @return the text color
152 | */
153 | public int getTextColor() {
154 | return textColor;
155 | }
156 |
157 | /**
158 | * Sets text color
159 | *
160 | * @param textColor
161 | * the text color to set
162 | */
163 | public void setTextColor(int textColor) {
164 | this.textColor = textColor;
165 | }
166 |
167 | /**
168 | * Gets text size
169 | *
170 | * @return the text size
171 | */
172 | public int getTextSize() {
173 | return textSize;
174 | }
175 |
176 | /**
177 | * Sets text size
178 | *
179 | * @param textSize
180 | * the text size to set
181 | */
182 | public void setTextSize(int textSize) {
183 | this.textSize = textSize;
184 | }
185 |
186 | /**
187 | * Gets resource Id for items views
188 | *
189 | * @return the item resource Id
190 | */
191 | public int getItemResource() {
192 | return itemResourceId;
193 | }
194 |
195 | /**
196 | * Sets resource Id for items views
197 | *
198 | * @param itemResourceId
199 | * the resource Id to set
200 | */
201 | public void setItemResource(int itemResourceId) {
202 | this.itemResourceId = itemResourceId;
203 | }
204 |
205 | /**
206 | * Gets resource Id for text view in item layout
207 | *
208 | * @return the item text resource Id
209 | */
210 | public int getItemTextResource() {
211 | return itemTextResourceId;
212 | }
213 |
214 | /**
215 | * Sets resource Id for text view in item layout
216 | *
217 | * @param itemTextResourceId
218 | * the item text resource Id to set
219 | */
220 | public void setItemTextResource(int itemTextResourceId) {
221 | this.itemTextResourceId = itemTextResourceId;
222 | }
223 |
224 | /**
225 | * Gets resource Id for empty items views
226 | *
227 | * @return the empty item resource Id
228 | */
229 | public int getEmptyItemResource() {
230 | return emptyItemResourceId;
231 | }
232 |
233 | /**
234 | * Sets resource Id for empty items views
235 | *
236 | * @param emptyItemResourceId
237 | * the empty item resource Id to set
238 | */
239 | public void setEmptyItemResource(int emptyItemResourceId) {
240 | this.emptyItemResourceId = emptyItemResourceId;
241 | }
242 |
243 | /**
244 | * Returns text for specified item
245 | *
246 | * @param index
247 | * the item index
248 | * @return the text of specified items
249 | */
250 | protected abstract CharSequence getItemText(int index);
251 |
252 | @Override
253 | public View getItem(int index, View convertView, ViewGroup parent) {
254 | if (index >= 0 && index < getItemsCount()) {
255 | if (convertView == null) {
256 | convertView = getView(itemResourceId, parent);
257 | }
258 | TextView textView = getTextView(convertView, itemTextResourceId);
259 | if (!arrayList.contains(textView)) {
260 | arrayList.add(textView);
261 | }
262 | if (textView != null) {
263 | CharSequence text = getItemText(index);
264 | if (text == null) {
265 | text = "";
266 | }
267 | textView.setText(text);
268 |
269 | if (index == currentIndex) {
270 | if (selColor != 0) {
271 | textView.setTextColor(selColor);
272 | }
273 | textView.setTextSize(maxsize);
274 | } else {
275 | if (unSelColor != 0) {
276 | textView.setTextColor(unSelColor);
277 | }
278 | textView.setTextSize(minsize);
279 | }
280 |
281 | if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {
282 | configureTextView(textView);
283 | }
284 | }
285 | return convertView;
286 | }
287 | return null;
288 | }
289 |
290 | @Override
291 | public View getEmptyItem(View convertView, ViewGroup parent) {
292 | if (convertView == null) {
293 | convertView = getView(emptyItemResourceId, parent);
294 | }
295 | if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {
296 | configureTextView((TextView) convertView);
297 | }
298 |
299 | return convertView;
300 | }
301 |
302 | public void setCurrentItem(int idx){
303 | currentIndex = idx;
304 | }
305 |
306 | /**
307 | * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.
308 | *
309 | * @param view
310 | * the text view to be configured
311 | */
312 | protected void configureTextView(TextView view) {
313 | view.setTextColor(textColor);
314 | view.setGravity(Gravity.CENTER);
315 | view.setTextSize(textSize);
316 | view.setLines(1);
317 | view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
318 | }
319 |
320 | /**
321 | * Loads a text view from view
322 | *
323 | * @param view
324 | * the text view or layout containing it
325 | * @param textResource
326 | * the text resource Id in layout
327 | * @return the loaded text view
328 | */
329 | private TextView getTextView(View view, int textResource) {
330 | TextView text = null;
331 | try {
332 | if (textResource == NO_RESOURCE && view instanceof TextView) {
333 | text = (TextView) view;
334 | } else if (textResource != NO_RESOURCE) {
335 | text = (TextView) view.findViewById(textResource);
336 | }
337 | } catch (ClassCastException e) {
338 | Log.e("AbstractWheelAdapter", "You must supply a resource ID for a TextView");
339 | throw new IllegalStateException("AbstractWheelAdapter requires the resource ID to be a TextView", e);
340 | }
341 |
342 | return text;
343 | }
344 |
345 | /**
346 | * Loads view from resources
347 | *
348 | * @param resource
349 | * the resource Id
350 | * @return the loaded view or null if resource is not set
351 | */
352 | private View getView(int resource, ViewGroup parent) {
353 | switch (resource) {
354 | case NO_RESOURCE:
355 | return null;
356 | case TEXT_VIEW_ITEM_RESOURCE:
357 | return new TextView(context);
358 | default:
359 | return inflater.inflate(resource, parent, false);
360 | }
361 | }
362 | }
363 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/adapters/AdapterWheel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package kankan.wheel.widget.adapters;
18 |
19 | import android.content.Context;
20 |
21 | import kankan.wheel.widget.WheelAdapter;
22 |
23 |
24 | /**
25 | * Adapter class for old wheel adapter (deprecated WheelAdapter class).
26 | *
27 | * @deprecated Will be removed soon
28 | */
29 | @Deprecated
30 | public class AdapterWheel extends AbstractWheelTextAdapter {
31 |
32 | // Source adapter
33 | private WheelAdapter adapter;
34 |
35 | /**
36 | * Constructor
37 | *
38 | * @param context
39 | * the current context
40 | * @param adapter
41 | * the source adapter
42 | */
43 | public AdapterWheel(Context context, WheelAdapter adapter) {
44 | super(context);
45 |
46 | this.adapter = adapter;
47 | }
48 |
49 | /**
50 | * Gets original adapter
51 | *
52 | * @return the original adapter
53 | */
54 | public WheelAdapter getAdapter() {
55 | return adapter;
56 | }
57 |
58 | @Override
59 | public int getItemsCount() {
60 | return adapter.getItemsCount();
61 | }
62 |
63 | @Override
64 | protected CharSequence getItemText(int index) {
65 | return adapter.getItem(index);
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/adapters/ArrayWheelAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package kankan.wheel.widget.adapters;
17 |
18 | import android.content.Context;
19 |
20 | /**
21 | * The simple Array wheel adapter
22 | *
23 | * @param
24 | * the element type
25 | */
26 | public class ArrayWheelAdapter extends AbstractWheelTextAdapter {
27 |
28 | // items
29 | private T items[];
30 |
31 | /**
32 | * Constructor
33 | *
34 | * @param context
35 | * the current context
36 | * @param items
37 | * the items
38 | */
39 | public ArrayWheelAdapter(Context context, T items[]) {
40 | super(context);
41 |
42 | // setEmptyItemResource(TEXT_VIEW_ITEM_RESOURCE);
43 | this.items = items;
44 | }
45 |
46 | @Override
47 | public CharSequence getItemText(int index) {
48 | if (index >= 0 && index < items.length) {
49 | T item = items[index];
50 | if (item instanceof CharSequence) {
51 | return (CharSequence) item;
52 | }
53 | return item.toString();
54 | }
55 | return null;
56 | }
57 |
58 | @Override
59 | public int getItemsCount() {
60 | return items.length;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/adapters/NumericWheelAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package kankan.wheel.widget.adapters;
18 |
19 | import android.content.Context;
20 |
21 | /**
22 | * Numeric Wheel adapter.
23 | */
24 | public class NumericWheelAdapter extends AbstractWheelTextAdapter {
25 |
26 | /** The default min value */
27 | public static final int DEFAULT_MAX_VALUE = 9;
28 |
29 | /** The default max value */
30 | private static final int DEFAULT_MIN_VALUE = 0;
31 |
32 | // Values
33 | private int minValue;
34 | private int maxValue;
35 |
36 | // format
37 | private String format;
38 |
39 | /**
40 | * Constructor
41 | *
42 | * @param context
43 | * the current context
44 | */
45 | public NumericWheelAdapter(Context context) {
46 | this(context, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);
47 | }
48 |
49 | /**
50 | * Constructor
51 | *
52 | * @param context
53 | * the current context
54 | * @param minValue
55 | * the wheel min value
56 | * @param maxValue
57 | * the wheel max value
58 | */
59 | public NumericWheelAdapter(Context context, int minValue, int maxValue) {
60 | this(context, minValue, maxValue, null);
61 | }
62 |
63 | /**
64 | * Constructor
65 | *
66 | * @param context
67 | * the current context
68 | * @param minValue
69 | * the wheel min value
70 | * @param maxValue
71 | * the wheel max value
72 | * @param format
73 | * the format string
74 | */
75 | public NumericWheelAdapter(Context context, int minValue, int maxValue, String format) {
76 | super(context);
77 |
78 | this.minValue = minValue;
79 | this.maxValue = maxValue;
80 | this.format = format;
81 | }
82 |
83 | @Override
84 | public CharSequence getItemText(int index) {
85 | if (index >= 0 && index < getItemsCount()) {
86 | int value = minValue + index;
87 | return format != null ? String.format(format, value) : Integer.toString(value);
88 | }
89 | return null;
90 | }
91 |
92 | @Override
93 | public int getItemsCount() {
94 | return maxValue - minValue + 1;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/wheel/src/main/java/kankan/wheel/widget/adapters/WheelViewAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Yuri Kanivets
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package kankan.wheel.widget.adapters;
18 |
19 | import android.database.DataSetObserver;
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 |
23 | /**
24 | * Wheel items adapter interface
25 | */
26 | public interface WheelViewAdapter {
27 | /**
28 | * Gets items count
29 | *
30 | * @return the count of wheel items
31 | */
32 | public int getItemsCount();
33 |
34 | /**
35 | * Get a View that displays the data at the specified position in the data
36 | * set
37 | *
38 | * @param index
39 | * the item index
40 | * @param convertView
41 | * the old view to reuse if possible
42 | * @param parent
43 | * the parent that this view will eventually be attached to
44 | * @return the wheel item View
45 | */
46 | public View getItem(int index, View convertView, ViewGroup parent);
47 |
48 | /**
49 | * Get a View that displays an empty wheel item placed before the first or
50 | * after the last wheel item.
51 | *
52 | * @param convertView
53 | * the old view to reuse if possible
54 | * @param parent
55 | * the parent that this view will eventually be attached to
56 | * @return the empty item View
57 | */
58 | public View getEmptyItem(View convertView, ViewGroup parent);
59 |
60 | /**
61 | * Register an observer that is called when changes happen to the data used
62 | * by this adapter.
63 | *
64 | * @param observer
65 | * the observer to be registered
66 | */
67 | public void registerDataSetObserver(DataSetObserver observer);
68 |
69 | /**
70 | * Unregister an observer that has previously been registered
71 | *
72 | * @param observer
73 | * the observer to be unregistered
74 | */
75 | void unregisterDataSetObserver(DataSetObserver observer);
76 | }
77 |
--------------------------------------------------------------------------------
/wheel/src/main/res/drawable/wheel_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/wheel/src/main/res/drawable/wheel_val.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
21 |
22 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/wheel/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | wheel
3 |
4 |
--------------------------------------------------------------------------------
/wheel/src/test/java/kankan/wheel/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package kankan.wheel;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------