Android 滑轮组件

今天开源一个时间滑轮组件,在网上有各种开源比如wheel和其它改写,多多少少不够实用和缺陷。

该项目地址位于:https://github.com/apple317/displayview

 

                                       Android 滑轮组件_第1张图片

            demo实现后效果图如上

 

1. 导入DisplayView(简称SDK)

        下载最新版sdk的zip包,解压将其中的download释放到本地目录,Eclipse用户右键您的工程根目录,选择Properties -> Java Build Path -> Libraries, 然后点击 Add External JARs... 选择指向download 的路径,点击OK,即导入成功。
下载最新版SDK的zip包,将其中的libs 文件夹合并到本地工程libs子目录下
Eclipse用户右键工程根目录,选择Properties -> Java Build Path -> Libraries,然后点击Add External JARs... 选择指向jar的路径,点击OK,即导入成功。
注意。

2.代码接入详解使用说明:

         在下载代码后,里面有参考代码,代码都有注释和调用详解,先讲解例子中RemFast调用类如何编写。

 

public class RemFast extends Activity {
	private LayoutInflater mInflater;
	private Context mcontext;
	private boolean wheelScrolled = false;
	// private DomobAdView mAdview320x50;
	private WheelView wheel_hours;
	private WheelView wheel_minute;
	private String remenderTime;
	private WheelView wheel_month;
	private WheelView wheel_day;
	private int beforeMonth = -1;
	private LinearLayout interGELinearLayout;
	public static final String[] HOUR_STRING = { "00", "01", "02", "03", "04",
			"05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15",
			"16", "17", "18", "19", "20", "21", "22", "23" };
	public static final String[] MINTUE_STRING = { "00", "01", "02", "03",
			"04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14",
			"15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
			"26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36",
			"37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47",
			"48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58",
			"59" };
	public static final String[] DAY_STRING = { "01", "02", "03", "04", "05",
			"06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16",
			"17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27",
			"28", "29", "30", "31" };
	public static final String[] MONTH_STRING = { "01", "02", "03", "04", "05",
			"06", "07", "08", "09", "10", "11", "12" };

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.layout_wheel);
		mcontext = this;
		mInflater = LayoutInflater.from(mcontext);
		createHead();
	}
	/**
	 * layout_remfast布局文件
	 * 
	 * 
	 * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/lay_content"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp" >
		<!-- 布局添加一个滑轮视图-->
        <com.apple.disview.WheelView
            android:id="@+id/fast_month"
            android:layout_width="0dip"
            android:layout_height="100dp"
            android:layout_gravity="center_vertical"
            android:layout_weight="1.0" />

        <com.apple.disview.WheelView
            android:id="@+id/fast_day"
            android:layout_width="0dip"
            android:layout_height="100dp"
            android:layout_gravity="center_vertical"
            android:layout_weight="1.0" />

        <com.apple.disview.WheelView
            android:id="@+id/fast_hours"
            android:layout_width="0dip"
            android:layout_height="100dp"
            android:layout_gravity="center_vertical"
            android:layout_weight="1.0" />

        <com.apple.disview.WheelView
            android:id="@+id/fast_mintue"
            android:layout_width="0dip"
            android:layout_height="100dp"
            android:layout_gravity="center_vertical"
            android:layout_weight="1.0" />
    </LinearLayout>

</LinearLayout>
	 * 
	 * 
	 * 
	 */

	private void createHead() {
		LinearLayout laymottom = (LinearLayout) findViewById(R.id.four_mottom);
		//创建一个滑轮子视图类
		View mottom = mInflater.inflate(R.layout.layout_remfast, null);
		//初始化一个滑轮视图对象
		wheel_month = (WheelView) mottom.findViewById(R.id.fast_month);
		//设置滑轮标记
		wheel_month.setTag("month");
		//设置滑轮数据集
		wheel_month.setAdapter(new ArrayWheelAdapter<String>(MONTH_STRING));
		//设置滑轮当前所在值
		wheel_month.setCurrentItem(wheel_month.getCurrentVal("02"));
		//设置滑轮是否可以循环滑动
		wheel_month.setCyclic(true);
		//设置滑轮标题
		wheel_month.setLabel("月");
		//添加滑轮变化监听事件
		wheel_month.addChangingListener(wheelChangeListener);
		//添加滑轮滚动变化监听事件
		wheel_month.addScrollingListener(wheelScrolledListener, null);
		wheel_day = (WheelView) mottom.findViewById(R.id.fast_day);
		wheel_day.setAdapter(new ArrayWheelAdapter<String>(DAY_STRING));
		wheel_day.setCurrentItem(3);
		wheel_day.setLabel("天");
		wheel_day.setTag("day");
		wheel_day.setCyclic(true);
		wheel_day.addChangingListener(wheelChangeListener);
		wheel_day.addScrollingListener(wheelScrolledListener, null);
		wheel_hours = (WheelView) mottom.findViewById(R.id.fast_hours);
		wheel_hours.setAdapter(new ArrayWheelAdapter<String>(HOUR_STRING));
		wheel_hours.setCyclic(true);
		wheel_hours.setTag("hours");
		wheel_minute = (WheelView) mottom.findViewById(R.id.fast_mintue);
		wheel_minute.setAdapter(new ArrayWheelAdapter<String>(MINTUE_STRING));
		wheel_minute.setCyclic(true);
		wheel_minute.setTag("minute");
		wheel_minute.setLabel("分钟");
		wheel_hours.setLabel("小时");
		wheel_hours.setCurrentItem(1);
		wheel_minute.setCurrentItem(2);
		wheel_minute.addScrollingListener(wheelScrolledListener, null);
		wheel_minute.addChangingListener(wheelChangeListener);
		wheel_minute.addScrollingListener(wheelScrolledListener, null);
		wheel_hours.addChangingListener(wheelChangeListener);
		wheel_hours.addScrollingListener(wheelScrolledListener, null);
		wheel_hours.setleftCheck(true);
		wheel_minute.setleftCheck(true);
		wheel_day.setleftCheck(true);
		laymottom.addView(mottom);
	}

	OnWheelScrollListener wheelScrolledListener = new OnWheelScrollListener() {
		public void onScrollingStarted(WheelView wheel) {
			wheelScrolled = true;
		}
		@Override
		public void onScrollingFinished(WheelView wheel) {
			// TODO Auto-generated method stub
			String tag = wheel.getTag().toString();
			wheelScrolled = false;
		}
	};

	// Wheel changed listener
	private OnWheelChangedListener wheelChangeListener = new OnWheelChangedListener() {
		@Override
		public void onLayChanged(WheelView wheel, int oldValue, int newValue,
				LinearLayout layout) {
			// TODO Auto-generated method stub

		}
	};

	
}

4.WheelView组件核心代码详解如下:

WheelView实现核心原理就是创建一个视图View,通过监听手势和滑动事件得到滑动距离,并绘画StaticLayout视图显示日期值。


public class WheelView extends View {
	/** Scrolling duration */
	private static final int SCROLLING_DURATION = 500;

	/** Minimum delta for scrolling */
	private static final int MIN_DELTA_FOR_SCROLLING = 1;

	/** Current value & label text color */
	private static final int VALUE_TEXT_COLOR = 0xF0000000;

	/** Items text color */
	private static final int ITEMS_TEXT_COLOR = 0xFF000000;

	/** Top and bottom shadows colors */
	private static final int[] SHADOWS_COLORS = new int[] { 0xFFfffbf7,
			0xFFffebda, 0xFFffebd9 };
	private static final int[] HSHADOWS_COLORS = new int[] { 0xFFe6e4e4,
			0xFF7d7c7c, 0x5e5d5d };
	private static final int[] BSHADOWS_COLORS = new int[] { 0x5e5d5d,
			0xFF7d7c7c, 0xFFe6e4e4 };
	/** Additional items height (is added to standard text item height) */
	/** Text size */
	private static float TEXT_SIZE = 24;// 24

	/** Default count of visible items */
	private static final int DEF_VISIBLE_ITEMS = 3;

	// Wheel Values
	private WheelAdapter adapter = null;
	private int currentItem = 0;

	// Widths
	private int itemsWidth = 0;
	private int labelWidth = 0;

	// Count of visible items
	private int visibleItems = DEF_VISIBLE_ITEMS;

	// Item height
	private int itemHeight = 0;

	// Text paints
	private TextPaint itemsPaint;
	private TextPaint valuePaint;

	// Layouts
	// private StaticLayout itemsLayout;
	private StaticLayout valueLayout;
	private StaticLayout srightLayout;
	private StaticLayout sleftLayout;
	// Label & background
	private String label;
	// Scrolling
	private boolean isScrollingPerformed;
	private int scrollingOffset;

	// Scrolling animation
	private GestureDetector gestureDetector;
	private Scroller scroller;
	private int lastScrollY;

	// Cyclic
	boolean isCyclic = true;

	// Listeners
	private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();
	private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();

	private Context mcontext;
	private onWheelClickListener wClick;

	private LinearLayout mlayout;
	private LinearLayout leftLayout;
	// type view
	private WheelView wview;
	private boolean single = false;
	private int mWidth;
	private int mHeight;

	private boolean leftCheck = false;

	/**
	 * Constructor
	 */
	public WheelView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mcontext = context;
		initData(context);
		wview = this;
	}

	/**
	 * Constructor
	 */
	public WheelView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mcontext = context;
		initData(context);
		wview = this;
	}

	/**
	 * Constructor
	 */
	public WheelView(Context context) {
		super(context);
		mcontext = context;
		initData(context);
		wview = this;
	}

	/**
	 * Initializes class data
	 * 
	 * @param context
	 *            the context
	 */
	private void initData(Context context) {
		gestureDetector = new GestureDetector(context, gestureListener);
		gestureDetector.setIsLongpressEnabled(false);
		scroller = new Scroller(context);

	}

	@Override
	protected void onFinishInflate() {
		// TODO Auto-generated method stub
		super.onFinishInflate();
//		Log.i("ZYN", "--->getHeight()"+getHeight());
//		
	}

	/**
	 * Gets wheel adapter
	 * 
	 * @return the adapter
	 */
	public WheelAdapter getAdapter() {
		return adapter;
	}

	/**
	 * Sets wheel adapter
	 * 
	 * @param adapter
	 *            the new wheel adapter
	 */
	public void setAdapter(WheelAdapter adapter) {
		this.adapter = adapter;
		invalidateLayouts();
		invalidate();
	}

	/**
	 * Set the the specified scrolling interpolator
	 * 
	 * @param interpolator
	 *            the interpolator
	 */
	public void setInterpolator(Interpolator interpolator) {
		scroller.forceFinished(true);
		scroller = new Scroller(getContext(), interpolator);
	}

	/**
	 * Gets count of visible items
	 * 
	 * @return the count of visible items
	 */
	public int getVisibleItems() {
		return visibleItems;
	}

	/**
	 * Sets count of visible items
	 * 
	 * @param count
	 *            the new count
	 */
	public void setVisibleItems(int count) {
		visibleItems = count;
		invalidate();
	}

	/**
	 * Gets label
	 * 
	 * @return the label
	 */
	public String getLabel() {
		return label;
	}

	/**
	 * Sets label
	 * 
	 * @param newLabel
	 *            the label to set
	 */
	public void setLabel(String newLabel) {
		label = newLabel;
	}

	/**
	 * 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.onLayChanged(this, oldValue, newValue, mlayout);
		}
	}

	/**
	 * Adds wheel scrolling listener
	 * 
	 * @param listener
	 *            the listener
	 */
	public void addScrollingListener(OnWheelScrollListener listener,
			GestureScrollView gs) {
		if (gs != null)
			gs.setGesture(gestureDetector);
		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);
		}
	}

	/**
	 * 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 (adapter == null || adapter.getItemsCount() == 0) {
			return; // throw?
		}
		if (index < 0 || index >= adapter.getItemsCount()) {
			if (isCyclic) {
				while (index < 0) {
					index += adapter.getItemsCount();
				}
				index %= adapter.getItemsCount();
			} else {
				return; // throw?
			}
		}
		if (index != currentItem) {
			if (animated) {
				scroll(index - currentItem, SCROLLING_DURATION);
			} else {
				invalidateLayouts();
				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;
		invalidate();
		invalidateLayouts();
	}

	/**
	 * Invalidates layouts
	 */
	private void invalidateLayouts() {
		valueLayout = null;
		valueLayout = null;
		scrollingOffset = 0;
	}

	/**
	 * Initializes resources
	 */
	private void initResourcesIfNecessary() {
		if (itemsPaint == null) {
			itemsPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG
					| Paint.FAKE_BOLD_TEXT_FLAG);
			itemsPaint.setTextSize(TEXT_SIZE);
			itemsPaint.setTextAlign(Align.CENTER);
		}

		if (valuePaint == null) {
			valuePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG
					| Paint.FAKE_BOLD_TEXT_FLAG | Paint.DITHER_FLAG);
			valuePaint.setTextSize(TEXT_SIZE);
			valuePaint.setShadowLayer(0.1f, 0, 0.1f, 0xFFC0C0C0);
			valuePaint.setTextAlign(Align.CENTER);
		}
		// setBackgroundResource(R.color.font_white);
	}

	/**
	 * Returns text item by index
	 * 
	 * @param index
	 *            the item index
	 * @return the item or null
	 */
	private String getTextItem(int index) {
		if (adapter == null || adapter.getItemsCount() == 0) {
			return null;
		}
		int count = adapter.getItemsCount();
		if ((index < 0 || index >= count) && !isCyclic) {
			return null;
		} else {
			while (index < 0) {
				index = count + index;
			}
		}
		index %= count;
		return adapter.getItem(index);
	}

	/**
	 * Builds text depending on current value
	 * 
	 * @param useCurrentValue
	 * @return the text
	 */
	private String buildText(boolean useCurrentValue) {
		StringBuilder itemsText = new StringBuilder();
		int addItems = visibleItems / 2 + 1;
		for (int i = currentItem - addItems; i <= currentItem + addItems; i++) {
			String text = getTextItem(i);
			if (text != null) {
				itemsText.append(text);
			}
			if (i < currentItem + addItems) {
				itemsText.append("\n");
			}
		}
		return itemsText.toString();
	}

	/**
	 * Returns height of wheel item
	 * 
	 * @return the item height
	 */
	private int getItemHeight() {
		if (itemHeight != 0) {
			return itemHeight;
		} else if (valueLayout != null && valueLayout.getLineCount() > 2) {
			itemHeight = valueLayout.getLineTop(2) - valueLayout.getLineTop(1);
			return itemHeight;
		}
		return getHeight() / visibleItems;
	}

	public int getCurrentVal(String itemVal) {
		int current = 0;
		for (int i = 0; i < adapter.getItemsCount(); i++) {
			if (getTextItem(i).equals(itemVal))
				current = i;
		}
		return current;
	}

	/**
	 * Creates layouts
	 * 
	 * @param widthItems
	 *            width of items layout
	 * @param widthLabel
	 *            width of label layout
	 */
	private void createLayouts() {
		String text = getAdapter() != null ? getAdapter().getItem(currentItem)
				: null;
		int itemHeight = (int) (mHeight / DEF_VISIBLE_ITEMS / 2 - TEXT_SIZE / 2);
		if (single) {
			sleftLayout = new StaticLayout("", valuePaint, 0,
					Layout.Alignment.ALIGN_CENTER, 1, 0.0F, false);
			valueLayout = new StaticLayout(buildText(isScrollingPerformed),
					valuePaint, this.getWidth() * 2 / 3,
					Layout.Alignment.ALIGN_NORMAL, 1, itemHeight * 2 - 4, false);
			srightLayout = new StaticLayout(label == null ? "" : label,
					valuePaint, this.getWidth() / 3,
					Layout.Alignment.ALIGN_CENTER, 1, itemHeight * 2 - 4, false);
		} else {
			sleftLayout = new StaticLayout("", valuePaint, this.getWidth() / 3,
					Layout.Alignment.ALIGN_CENTER, 1, 0.0F, false);
			valueLayout = new StaticLayout(buildText(isScrollingPerformed),
					valuePaint, this.getWidth() / 3,
					Layout.Alignment.ALIGN_NORMAL, 1, itemHeight * 2 - 4, false);
			srightLayout = new StaticLayout(label == null ? "" : label,
					valuePaint, this.getWidth() / 3,
					Layout.Alignment.ALIGN_CENTER, 1, itemHeight * 2 - 4, false);
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		initResourcesIfNecessary();
		createLayouts();
		drawValue(canvas);
		canvas.restore();
		Rect r = new Rect();
		Shader mShader = new LinearGradient(0, 0, 100, 100, SHADOWS_COLORS,
				new float[] { 0, 0.5f, 1.0f }, Shader.TileMode.CLAMP);
		Shader hCheckShader = new LinearGradient(0, 0, 100, 100,
				HSHADOWS_COLORS, new float[] { 0, 0.5f, 1.0f },
				Shader.TileMode.CLAMP);
		Shader bCheckShader = new LinearGradient(0, 0, 100, 100,
				BSHADOWS_COLORS, new float[] { 0, 0.5f, 1.0f },
				Shader.TileMode.CLAMP);
		Paint p = new Paint();
		p.setAntiAlias(true);
		p.setShader(mShader);
		p.setAlpha(127);
		r.left = 0;
		r.top = mHeight / 3;
		r.right = r.left + this.getWidth();
		r.bottom = mHeight / 3 + r.top;
		canvas.drawRect(r, p);
		if (leftCheck) {
			p.setShader(hCheckShader);
			p.setStyle(Paint.Style.FILL);
			Rect rCheck = new Rect();
			rCheck.left = 0;
			rCheck.top = 0;
			rCheck.right = 1;
			rCheck.bottom = (r.bottom + mHeight / 3) / 2;
			canvas.drawRect(rCheck, p);
			p.setShader(bCheckShader);
			Rect bCheck = new Rect();
			bCheck.left = 0;
			bCheck.top = (r.bottom + mHeight / 3) / 2;
			bCheck.right = 1;
			bCheck.bottom = r.bottom + mHeight / 3;
			canvas.drawRect(bCheck, p);
			// Paint rline = new Paint();
			// rline.setStyle(Paint.Style.STROKE);
			// rline.setTextSkewX((float) 3.0);
			// rline.setColor(0xFFffd5b0);
			// canvas.drawLine(0,0,0,r.bottom+mHeight/3, rline);//
		}
		Paint pline = new Paint();
		pline.setColor(0xFFffd5b0);
		pline.setStyle(Paint.Style.FILL);
		pline.setTextSkewX((float) 3.0);
		canvas.drawLine(0, r.top, r.right, r.top, pline);
		canvas.drawLine(0, r.bottom, r.right, r.bottom, pline);//
		canvas.drawLine(0, r.top, 0, r.bottom, pline);//
		canvas.drawLine(r.right, r.top, r.right, r.bottom, pline);//
	}

	/**
	 * Draws value and label layout
	 * 
	 * @param canvas
	 *            the canvas for drawing
	 */
	private void drawValue(Canvas canvas) {
		canvas.save();
		valuePaint.setColor(VALUE_TEXT_COLOR);
		valuePaint.drawableState = getDrawableState();
		int itemHeight = (int) (mHeight / DEF_VISIBLE_ITEMS / 2 - TEXT_SIZE / 2);
		Rect bounds = new Rect();
		if (single) {
			if (sleftLayout != null) {
				canvas.save();
				canvas.translate(0, bounds.top);
				sleftLayout.draw(canvas);
				canvas.restore();
			}
			// // draw label
			if (srightLayout != null) {
				canvas.save();
				canvas.translate((this.getWidth() / 3) * 2, itemHeight * 3
						+ TEXT_SIZE);
				srightLayout.draw(canvas);
				canvas.restore();
			}
			// draw current value
			if (valueLayout != null) {
				canvas.save();
				int top = valueLayout.getLineTop(1);
				//通过游标平移高度
				//其实每次滑动后都会通过View重新绘画走到这里。
				canvas.translate(this.getWidth() / 3
						+ (valueLayout.getWidth() / 11) * 2, -top
						+ scrollingOffset + itemHeight);
				itemsPaint.setColor(ITEMS_TEXT_COLOR);
				itemsPaint.drawableState = getDrawableState();
				valueLayout.draw(canvas);
				canvas.restore();
			}
		} else {
			if (sleftLayout != null) {
				canvas.save();
				canvas.translate(this.getWidth() / 4, bounds.top);
				sleftLayout.draw(canvas);
				canvas.restore();
			}
			// draw label
			if (srightLayout != null) {
				canvas.save();
				canvas.translate((this.getWidth() / 3) * 2, itemHeight * 3
						+ TEXT_SIZE);
				srightLayout.draw(canvas);
				canvas.restore();
			}
			// draw current value
			if (valueLayout != null) {
				canvas.save();
				int top = valueLayout.getLineTop(1);
				canvas.translate(this.getWidth() / 3
						+ (valueLayout.getWidth() / 11) * 5, -top
						+ scrollingOffset + itemHeight);
				itemsPaint.setColor(ITEMS_TEXT_COLOR);
				itemsPaint.drawableState = getDrawableState();
				valueLayout.draw(canvas);
				canvas.restore();
			}
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		WheelAdapter adapter = getAdapter();
		if (adapter == null) {
			return true;
		}
		if (!gestureDetector.onTouchEvent(event)
				&& event.getAction() == MotionEvent.ACTION_UP)
			justify();
		return true;
	}

	/**
	 * Scrolls the wheel
	 * 
	 * @param delta
	 *            the scrolling value
	 */
	private void doScroll(int delta) {
		scrollingOffset += delta;
		int count = scrollingOffset / getItemHeight();
		int pos = currentItem - count;
		if (isCyclic && adapter.getItemsCount() > 0) {
			// fix position by rotating
			while (pos < 0) {
				pos += adapter.getItemsCount();
			}
			pos %= adapter.getItemsCount();
		} else if (isScrollingPerformed) {
			//
			if (pos < 0) {
				count = currentItem;
				pos = 0;
			} else if (pos >= adapter.getItemsCount()) {
				count = currentItem - adapter.getItemsCount() + 1;
				pos = adapter.getItemsCount() - 1;
			}
		} else {
			// fix position
			pos = Math.max(pos, 0);
			pos = Math.min(pos, adapter.getItemsCount() - 1);
		}

		int offset = scrollingOffset;
		if (pos != currentItem) {
			setCurrentItem(pos, false);
		} else {
			invalidate();
		}

		// update offset
		scrollingOffset = offset - count * getItemHeight();
		if (scrollingOffset > getHeight()) {
			scrollingOffset = scrollingOffset % getHeight() + getHeight();
		}
	}

	// gesture listener
	private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
		public boolean onDown(MotionEvent e) {
			if (wview.getTag() != null && wClick != null)
				wClick.onClick(wview.getTag());
			if (isScrollingPerformed) {
				scroller.forceFinished(true);
				clearMessages();
				return true;
			}
			return false;
		}

		public boolean onScroll(MotionEvent e1, MotionEvent e2,
				float distanceX, float distanceY) {
			startScrolling();
			doScroll((int) -distanceY);
			return true;
		}

		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			lastScrollY = currentItem * getItemHeight() + scrollingOffset;
			int maxY = isCyclic ? 0x7FFFFFFF : adapter.getItemsCount()
					* getItemHeight();
			int minY = isCyclic ? -maxY : 0;
			scroller.fling(0, lastScrollY, 0, (int) -velocityY / 2, 0, 0, minY,
					maxY);
			setNextMessage(MESSAGE_SCROLL);
			return true;
		}

		@Override
		public boolean onSingleTapUp(MotionEvent e) {
			// TODO Auto-generated method stub
			return super.onSingleTapUp(e);
		}

	};

	// Messages
	private final int MESSAGE_SCROLL = 0;
	private final int MESSAGE_JUSTIFY = 1;

	/**
	 * Set next message to queue. Clears queue before.
	 * 
	 * @param message
	 *            the message to set
	 */
	private void setNextMessage(int message) {
		clearMessages();
		animationHandler.sendEmptyMessage(message);
	}

	/**
	 * Clears messages from queue
	 */
	private void clearMessages() {
		animationHandler.removeMessages(MESSAGE_SCROLL);
		animationHandler.removeMessages(MESSAGE_JUSTIFY);
	}

	// animation handler
	private Handler animationHandler = new Handler() {
		public void handleMessage(Message msg) {
			scroller.computeScrollOffset();
			int currY = scroller.getCurrY();
			int delta = lastScrollY - currY;
			lastScrollY = currY;
			if (delta != 0) {
				doScroll(delta);
			}

			// scrolling is not finished when it comes to final Y
			// so, finish it manually
			if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {
				currY = scroller.getFinalY();
				scroller.forceFinished(true);
			}
			if (!scroller.isFinished()) {
				animationHandler.sendEmptyMessage(msg.what);
			} else if (msg.what == MESSAGE_SCROLL) {
				justify();
			} else {
				finishScrolling();
			}
		}
	};

	/**
	 * Justifies wheel
	 */
	private void justify() {
		if (adapter == null) {
			return;
		}
		lastScrollY = 0;
		int offset = scrollingOffset;
		int itemHeight = getItemHeight();
		boolean needToIncrease = offset > 0 ? currentItem < adapter
				.getItemsCount() : currentItem > 0;
		if ((isCyclic || needToIncrease)
				&& Math.abs((float) offset) > (float) itemHeight / 2) {
			if (offset < 0)
				offset += itemHeight + MIN_DELTA_FOR_SCROLLING;
			else
				offset -= itemHeight + MIN_DELTA_FOR_SCROLLING;
		}
		if (Math.abs(offset) > MIN_DELTA_FOR_SCROLLING) {
			scroller.startScroll(0, 0, 0, offset, SCROLLING_DURATION);
			setNextMessage(MESSAGE_JUSTIFY);
		} else {
			finishScrolling();
		}
	}

	/**
	 * Starts scrolling
	 */
	private void startScrolling() {
		if (!isScrollingPerformed) {
			isScrollingPerformed = true;
			notifyScrollingListenersAboutStart();
		}
	}

	/**
	 * Finishes scrolling
	 */
	void finishScrolling() {
		if (isScrollingPerformed) {
			notifyScrollingListenersAboutEnd();
			isScrollingPerformed = false;
		}
		invalidateLayouts();
		invalidate();
	}

	/**
	 * Scroll the wheel
	 * 
	 * @param itemsToSkip
	 *            items to scroll
	 * @param time
	 *            scrolling duration
	 */
	public void scroll(int itemsToScroll, int time) {
		scroller.forceFinished(true);
		lastScrollY = scrollingOffset;
		int offset = itemsToScroll * getItemHeight();
		scroller.startScroll(0, lastScrollY, 0, offset - lastScrollY, time);
		setNextMessage(MESSAGE_SCROLL);
		startScrolling();
	}

	public void setWheelClick(onWheelClickListener l) {
		wClick = l;
	}

	public void setSingle() {
		single = true;
	}

	public void setViewHeight(int height) {
		mHeight = height;
	}

	public void setleftCheck(boolean mleftCheck) {
		leftCheck = mleftCheck;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		mHeight =heightSize;
		setMeasuredDimension(widthSize, heightSize);
	}
}



 

你可能感兴趣的:(Wheel,Android滑轮,时间滑轮,wheel完善版)