diff options
Diffstat (limited to 'platform/java/src/kankan/wheel/widget/WheelView.java')
-rw-r--r-- | platform/java/src/kankan/wheel/widget/WheelView.java | 889 |
1 files changed, 0 insertions, 889 deletions
diff --git a/platform/java/src/kankan/wheel/widget/WheelView.java b/platform/java/src/kankan/wheel/widget/WheelView.java deleted file mode 100644 index e8324e88..00000000 --- a/platform/java/src/kankan/wheel/widget/WheelView.java +++ /dev/null @@ -1,889 +0,0 @@ -/* - * Android Wheel Control. - * https://code.google.com/p/android-wheel/ - * - * Copyright 2011 Yuri Kanivets - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package kankan.wheel.widget; - -import android.content.Context; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.GradientDrawable.Orientation; -import android.media.AudioManager; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.SoundEffectConstants; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.animation.Interpolator; -import android.widget.LinearLayout; - -import com.artifex.mupdf.fitz.R; - -import java.util.LinkedList; -import java.util.List; - -import kankan.wheel.widget.adapters.WheelViewAdapter; - - - -/** - * Numeric wheel view. - * - * @author Yuri Kanivets - */ -public class WheelView extends View { - - /** Top and bottom shadows colors */ - private static final int[] SHADOWS_COLORS = new int[] { 0xFF111111, - 0x00AAAAAA, 0x00AAAAAA }; - - /** Top and bottom items offset (to hide that) */ - private static final int ITEM_OFFSET_PERCENT = 10; - - /** Left and right padding value */ - private static final int PADDING = 10; - - /** Default count of visible items */ - private static final int DEF_VISIBLE_ITEMS = 5; - - // Wheel Values - private int currentItem = 0; - - // Count of visible items - private int visibleItems = DEF_VISIBLE_ITEMS; - - // Item height - private int itemHeight = 0; - - // Center Line - private Drawable centerDrawable; - - // // Shadows drawables - private GradientDrawable topShadow; - private GradientDrawable bottomShadow; - - // Scrolling - private WheelScroller scroller; - private boolean isScrollingPerformed; - private int scrollingOffset; - - // Cyclic - boolean isCyclic = false; - - // Items layout - private LinearLayout itemsLayout; - - // The number of first item in layout - private int firstItem; - - // View adapter - private WheelViewAdapter viewAdapter; - - // Recycle - private WheelRecycle recycle = new WheelRecycle(this); - - // Listeners - private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>(); - private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>(); - private List<OnWheelClickedListener> clickingListeners = new LinkedList<OnWheelClickedListener>(); - - /** - * Constructor - */ - public WheelView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initData(context); - } - - /** - * Constructor - */ - public WheelView(Context context, AttributeSet attrs) { - super(context, attrs); - initData(context); - } - - /** - * Constructor - */ - public WheelView(Context context) { - super(context); - initData(context); - } - - /** - * Initializes class data - * @param context the context - */ - private void initData(Context context) { - scroller = new WheelScroller(getContext(), scrollingListener); - } - - // Scrolling listener - WheelScroller.ScrollingListener scrollingListener = new WheelScroller.ScrollingListener() { - public void onStarted() { - isScrollingPerformed = true; - notifyScrollingListenersAboutStart(); - } - - public void onScroll(int distance) { - doScroll(distance); - - int height = getHeight(); - if (scrollingOffset > height) { - scrollingOffset = height; - scroller.stopScrolling(); - } else if (scrollingOffset < -height) { - scrollingOffset = -height; - scroller.stopScrolling(); - } - } - - public void onFinished() { - if (isScrollingPerformed) { - notifyScrollingListenersAboutEnd(); - isScrollingPerformed = false; - } - - scrollingOffset = 0; - invalidate(); - } - - public void onJustify() { - if (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) { - scroller.scroll(scrollingOffset, 0); - } - } - }; - - /** - * Set the the specified scrolling interpolator - * @param interpolator the interpolator - */ - public void setInterpolator(Interpolator interpolator) { - scroller.setInterpolator(interpolator); - } - - /** - * Gets count of visible items - * - * @return the count of visible items - */ - public int getVisibleItems() { - return visibleItems; - } - - /** - * Sets the desired count of visible items. - * Actual amount of visible items depends on wheel layout parameters. - * To apply changes and rebuild view call measure(). - * - * @param count the desired count for visible items - */ - public void setVisibleItems(int count) { - visibleItems = count; - } - - /** - * Gets view adapter - * @return the view adapter - */ - public WheelViewAdapter getViewAdapter() { - return viewAdapter; - } - - // Adapter listener - private DataSetObserver dataObserver = new DataSetObserver() { - @Override - public void onChanged() { - invalidateWheel(false); - } - - @Override - public void onInvalidated() { - invalidateWheel(true); - } - }; - - /** - * Sets view adapter. Usually new adapters contain different views, so - * it needs to rebuild view by calling measure(). - * - * @param viewAdapter the view adapter - */ - public void setViewAdapter(WheelViewAdapter viewAdapter) { - if (this.viewAdapter != null) { - this.viewAdapter.unregisterDataSetObserver(dataObserver); - } - this.viewAdapter = viewAdapter; - if (this.viewAdapter != null) { - this.viewAdapter.registerDataSetObserver(dataObserver); - } - - invalidateWheel(true); - } - - /** - * Adds wheel changing listener - * @param listener the listener - */ - public void addChangingListener(OnWheelChangedListener listener) { - changingListeners.add(listener); - } - - /** - * Removes wheel changing listener - * @param listener the listener - */ - public void removeChangingListener(OnWheelChangedListener listener) { - changingListeners.remove(listener); - } - - /** - * Notifies changing listeners - * @param oldValue the old wheel value - * @param newValue the new wheel value - */ - protected void notifyChangingListeners(int oldValue, int newValue) { - for (OnWheelChangedListener listener : changingListeners) { - listener.onChanged(this, oldValue, newValue); - } - - // play a sound. - // TODO: something better - this.playSoundEffect(SoundEffectConstants.CLICK); - } - - /** - * Adds wheel scrolling listener - * @param listener the listener - */ - public void addScrollingListener(OnWheelScrollListener listener) { - scrollingListeners.add(listener); - } - - /** - * Removes wheel scrolling listener - * @param listener the listener - */ - public void removeScrollingListener(OnWheelScrollListener listener) { - scrollingListeners.remove(listener); - } - - /** - * Notifies listeners about starting scrolling - */ - protected void notifyScrollingListenersAboutStart() { - for (OnWheelScrollListener listener : scrollingListeners) { - listener.onScrollingStarted(this); - } - } - - /** - * Notifies listeners about ending scrolling - */ - protected void notifyScrollingListenersAboutEnd() { - for (OnWheelScrollListener listener : scrollingListeners) { - listener.onScrollingFinished(this); - } - } - - /** - * Adds wheel clicking listener - * @param listener the listener - */ - public void addClickingListener(OnWheelClickedListener listener) { - clickingListeners.add(listener); - } - - /** - * Removes wheel clicking listener - * @param listener the listener - */ - public void removeClickingListener(OnWheelClickedListener listener) { - clickingListeners.remove(listener); - } - - /** - * Notifies listeners about clicking - */ - protected void notifyClickListenersAboutClick(int item) { - for (OnWheelClickedListener listener : clickingListeners) { - listener.onItemClicked(this, item); - } - } - - /** - * Gets current value - * - * @return the current value - */ - public int getCurrentItem() { - return currentItem; - } - - /** - * Sets the current item. Does nothing when index is wrong. - * - * @param index the item index - * @param animated the animation flag - */ - public void setCurrentItem(int index, boolean animated) { - if (viewAdapter == null || viewAdapter.getItemsCount() == 0) { - return; // throw? - } - - int itemCount = viewAdapter.getItemsCount(); - if (index < 0 || index >= itemCount) { - if (isCyclic) { - while (index < 0) { - index += itemCount; - } - index %= itemCount; - } else{ - return; // throw? - } - } - if (index != currentItem) { - if (animated) { - int itemsToScroll = index - currentItem; - if (isCyclic) { - int scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem); - if (scroll < Math.abs(itemsToScroll)) { - itemsToScroll = itemsToScroll < 0 ? scroll : -scroll; - } - } - scroll(itemsToScroll, 0); - } else { - scrollingOffset = 0; - - int old = currentItem; - currentItem = index; - - notifyChangingListeners(old, currentItem); - - invalidate(); - } - } - } - - /** - * Sets the current item w/o animation. Does nothing when index is wrong. - * - * @param index the item index - */ - public void setCurrentItem(int index) { - setCurrentItem(index, false); - } - - /** - * Tests if wheel is cyclic. That means before the 1st item there is shown the last one - * @return true if wheel is cyclic - */ - public boolean isCyclic() { - return isCyclic; - } - - /** - * Set wheel cyclic flag - * @param isCyclic the flag to set - */ - public void setCyclic(boolean isCyclic) { - this.isCyclic = isCyclic; - invalidateWheel(false); - } - - /** - * Invalidates wheel - * @param clearCaches if true then cached views will be clear - */ - public void invalidateWheel(boolean clearCaches) { - if (clearCaches) { - recycle.clearAll(); - if (itemsLayout != null) { - itemsLayout.removeAllViews(); - } - scrollingOffset = 0; - } else if (itemsLayout != null) { - // cache all items - recycle.recycleItems(itemsLayout, firstItem, new ItemsRange()); - } - - invalidate(); - } - - /** - * Initializes resources - */ - private void initResourcesIfNecessary() { - if (centerDrawable == null) { - centerDrawable = getContext().getResources().getDrawable(R.drawable.wheel_val); - } - - if (topShadow == null) { - topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS); - } - - if (bottomShadow == null) { - bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS); - } - - setBackgroundResource(R.drawable.wheel_bg); - } - - /** - * Calculates desired height for layout - * - * @param layout - * the source layout - * @return the desired layout height - */ - private int getDesiredHeight(LinearLayout layout) { - if (layout != null && layout.getChildAt(0) != null) { - itemHeight = layout.getChildAt(0).getMeasuredHeight(); - } - - int desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50; - - return Math.max(desired, getSuggestedMinimumHeight()); - } - - /** - * Returns height of wheel item - * @return the item height - */ - private int getItemHeight() { - if (itemHeight != 0) { - return itemHeight; - } - - if (itemsLayout != null && itemsLayout.getChildAt(0) != null) { - itemHeight = itemsLayout.getChildAt(0).getHeight(); - return itemHeight; - } - - return getHeight() / visibleItems; - } - - /** - * Calculates control width and creates text layouts - * @param widthSize the input layout width - * @param mode the layout mode - * @return the calculated control width - */ - private int calculateLayoutWidth(int widthSize, int mode) { - initResourcesIfNecessary(); - - // TODO: make it static - itemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - itemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED), - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - int width = itemsLayout.getMeasuredWidth(); - - if (mode == MeasureSpec.EXACTLY) { - width = widthSize; - } else { - width += 2 * PADDING; - - // Check against our minimum width - width = Math.max(width, getSuggestedMinimumWidth()); - - if (mode == MeasureSpec.AT_MOST && widthSize < width) { - width = widthSize; - } - } - - itemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - - return width; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - buildViewForMeasuring(); - - int width = calculateLayoutWidth(widthSize, widthMode); - - int height; - if (heightMode == MeasureSpec.EXACTLY) { - height = heightSize; - } else { - height = getDesiredHeight(itemsLayout); - - if (heightMode == MeasureSpec.AT_MOST) { - height = Math.min(height, heightSize); - } - } - - setMeasuredDimension(width, height); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - layout(r - l, b - t); - } - - /** - * Sets layouts width and height - * @param width the layout width - * @param height the layout height - */ - private void layout(int width, int height) { - int itemsWidth = width - 2 * PADDING; - - itemsLayout.layout(0, 0, itemsWidth, height); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (viewAdapter != null && viewAdapter.getItemsCount() > 0) { - updateView(); - - drawItems(canvas); - drawCenterRect(canvas); - } - -// drawShadows(canvas); - } - - /** - * Draws shadows on top and bottom of control - * @param canvas the canvas for drawing - */ - private void drawShadows(Canvas canvas) { - int height = (int)(1.5 * getItemHeight()); - topShadow.setBounds(0, 0, getWidth(), height); - topShadow.draw(canvas); - - bottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight()); - bottomShadow.draw(canvas); - } - - /** - * Draws items - * @param canvas the canvas for drawing - */ - private void drawItems(Canvas canvas) { - canvas.save(); - - int top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2; - canvas.translate(PADDING, - top + scrollingOffset); - - itemsLayout.draw(canvas); - - canvas.restore(); - } - - /** - * Draws rect for current value - * @param canvas the canvas for drawing - */ - private void drawCenterRect(Canvas canvas) { - int center = getHeight() / 2; - int offset = (int) (getItemHeight() / 2 * 1.2); - centerDrawable.setBounds(0, center - offset, getWidth(), center + offset); - centerDrawable.draw(canvas); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (!isEnabled() || getViewAdapter() == null) { - return true; - } - - switch (event.getAction()) { - case MotionEvent.ACTION_MOVE: - if (getParent() != null) { - getParent().requestDisallowInterceptTouchEvent(true); - } - break; - - case MotionEvent.ACTION_UP: - if (!isScrollingPerformed) { - int distance = (int) event.getY() - getHeight() / 2; - if (distance > 0) { - distance += getItemHeight() / 2; - } else { - distance -= getItemHeight() / 2; - } - int items = distance / getItemHeight(); - if (items != 0 && isValidItemIndex(currentItem + items)) { - notifyClickListenersAboutClick(currentItem + items); - } - } - break; - } - - return scroller.onTouchEvent(event); - } - - /** - * Scrolls the wheel - * @param delta the scrolling value - */ - private void doScroll(int delta) { - scrollingOffset += delta; - - int itemHeight = getItemHeight(); - int count = scrollingOffset / itemHeight; - - int pos = currentItem - count; - int itemCount = viewAdapter.getItemsCount(); - - int fixPos = scrollingOffset % itemHeight; - if (Math.abs(fixPos) <= itemHeight / 2) { - fixPos = 0; - } - if (isCyclic && itemCount > 0) { - if (fixPos > 0) { - pos--; - count++; - } else if (fixPos < 0) { - pos++; - count--; - } - // fix position by rotating - while (pos < 0) { - pos += itemCount; - } - pos %= itemCount; - } else { - // - if (pos < 0) { - count = currentItem; - pos = 0; - } else if (pos >= itemCount) { - count = currentItem - itemCount + 1; - pos = itemCount - 1; - } else if (pos > 0 && fixPos > 0) { - pos--; - count++; - } else if (pos < itemCount - 1 && fixPos < 0) { - pos++; - count--; - } - } - - int offset = scrollingOffset; - if (pos != currentItem) { - setCurrentItem(pos, false); - } else { - invalidate(); - } - - // update offset - scrollingOffset = offset - count * itemHeight; - if (scrollingOffset > getHeight()) { - scrollingOffset = scrollingOffset % getHeight() + getHeight(); - } - } - - /** - * Scroll the wheel - * @param itemsToSkip items to scroll - * @param time scrolling duration - */ - public void scroll(int itemsToScroll, int time) { - int distance = itemsToScroll * getItemHeight() - scrollingOffset; - scroller.scroll(distance, time); - } - - /** - * Calculates range for wheel items - * @return the items range - */ - private ItemsRange getItemsRange() { - if (getItemHeight() == 0) { - return null; - } - - int first = currentItem; - int count = 1; - - while (count * getItemHeight() < getHeight()) { - first--; - count += 2; // top + bottom items - } - - if (scrollingOffset != 0) { - if (scrollingOffset > 0) { - first--; - } - count++; - - // process empty items above the first or below the second - int emptyItems = scrollingOffset / getItemHeight(); - first -= emptyItems; - count += Math.asin(emptyItems); - } - return new ItemsRange(first, count); - } - - /** - * Rebuilds wheel items if necessary. Caches all unused items. - * - * @return true if items are rebuilt - */ - private boolean rebuildItems() { - boolean updated = false; - ItemsRange range = getItemsRange(); - if (itemsLayout != null) { - int first = recycle.recycleItems(itemsLayout, firstItem, range); - updated = firstItem != first; - firstItem = first; - } else { - createItemsLayout(); - updated = true; - } - - if (!updated) { - updated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount(); - } - - if (firstItem > range.getFirst() && firstItem <= range.getLast()) { - for (int i = firstItem - 1; i >= range.getFirst(); i--) { - if (!addViewItem(i, true)) { - break; - } - firstItem = i; - } - } else { - firstItem = range.getFirst(); - } - - int first = firstItem; - for (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) { - if (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) { - first++; - } - } - firstItem = first; - - return updated; - } - - /** - * Updates view. Rebuilds items and label if necessary, recalculate items sizes. - */ - private void updateView() { - if (rebuildItems()) { - calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY); - layout(getWidth(), getHeight()); - } - } - - /** - * Creates item layouts if necessary - */ - private void createItemsLayout() { - if (itemsLayout == null) { - itemsLayout = new LinearLayout(getContext()); - itemsLayout.setOrientation(LinearLayout.VERTICAL); - } - } - - /** - * Builds view for measuring - */ - private void buildViewForMeasuring() { - // clear all items - if (itemsLayout != null) { - recycle.recycleItems(itemsLayout, firstItem, new ItemsRange()); - } else { - createItemsLayout(); - } - - // add views - int addItems = visibleItems / 2; - for (int i = currentItem + addItems; i >= currentItem - addItems; i--) { - if (addViewItem(i, true)) { - firstItem = i; - } - } - } - - /** - * Adds view for item to items layout - * @param index the item index - * @param first the flag indicates if view should be first - * @return true if corresponding item exists and is added - */ - private boolean addViewItem(int index, boolean first) { - View view = getItemView(index); - if (view != null) { - if (first) { - itemsLayout.addView(view, 0); - } else { - itemsLayout.addView(view); - } - - return true; - } - - return false; - } - - /** - * Checks whether intem index is valid - * @param index the item index - * @return true if item index is not out of bounds or the wheel is cyclic - */ - private boolean isValidItemIndex(int index) { - return viewAdapter != null && viewAdapter.getItemsCount() > 0 && - (isCyclic || index >= 0 && index < viewAdapter.getItemsCount()); - } - - /** - * Returns view for specified item - * @param index the item index - * @return item view or empty view if index is out of bounds - */ - private View getItemView(int index) { - if (viewAdapter == null || viewAdapter.getItemsCount() == 0) { - return null; - } - int count = viewAdapter.getItemsCount(); - if (!isValidItemIndex(index)) { - return viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout); - } else { - while (index < 0) { - index = count + index; - } - } - - index %= count; - return viewAdapter.getItem(index, recycle.getItem(), itemsLayout); - } - - /** - * Stops scrolling - */ - public void stopScrolling() { - scroller.stopScrolling(); - } -} |