Android自定义控件实战——滚动选择器PickerView



    

Android自定义控件实战——滚动选择器PickerView

标签: androidTimerPickerPickerView

2014-08-12 11:57 10014人阅读 评论(39) 收藏 举报

本文章已收录于:

分类:

Android(10)

作者同类文章X

版权声明:本文为博主原创文章,未经博主允许不得转载。

   转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38513301

  手机里设置闹钟需要选择时间,那个选择时间的控件就是滚动选择器,前几天用手机刷了MIUI,发现自带的那个时间选择器效果挺好看的,于是就自己仿写了一个,权当练手。先来看效果:

                                                                 

效果还行吧?实现思路就是自定义一个PickerView,单独滚动的是一个PickerView,显然上图中有分和秒的选择所以在布局里用了两个PickerView。由于这里不涉及到text的点击事件,所以只需要继承View就行了,直接把text用canvas画上去。PickerView的实现的主要难点:

难点1:

        字体随距离的渐变。可以看到,text随离中心位置的距离变化而变化,这里变化的是透明度alpha和字体大小TexSize,这两个值我都设置了Max和Min值,通过其与中心点的距离计算scale。我用的是变化曲线是抛物线scale=1-ax^2(x<=Height/4),scale = 0(x>Height/4),a=(4/Height)^2。x就是距离View中心的偏移量。用图片表示如下:

难点2:

     text的居中。绘制text的时候不仅要使其在x方向上居中,还要在y方向上居中,在x方向上比较简单,设置Paint的Align为Align.CENTER就行了,但是y方向上很蛋疼,需要计算text的baseline。

难点3:

    循环滚动。为了解决循环滚动的问题我把存放text的List从中间往上下摊开,通过不断地moveHeadToTail和moveTailToHead使选中的text始终是list的中间position的值。

  

     以上就是几个难点,了解了之后可以来看PickerView的代码了:

 

[java] view plain copy print?

  1. package com.jingchen.timerpicker;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5. import java.util.Timer;  
  6. import java.util.TimerTask;  
  7.   
  8. import android.content.Context;  
  9. import android.graphics.Canvas;  
  10. import android.graphics.Paint;  
  11. import android.graphics.Paint.Align;  
  12. import android.graphics.Paint.FontMetricsInt;  
  13. import android.graphics.Paint.Style;  
  14. import android.os.Handler;  
  15. import android.os.Message;  
  16. import android.util.AttributeSet;  
  17. import android.view.MotionEvent;  
  18. import android.view.View;  
  19.   
  20. /** 
  21.  * 滚动选择器 
  22.  *  
  23.  * @author chenjing 
  24.  *  
  25.  */  
  26. public class PickerView extends View  
  27. {  
  28.   
  29.     public static final String TAG = "PickerView";  
  30.     /** 
  31.      * text之间间距和minTextSize之比 
  32.      */  
  33.     public static final float MARGIN_ALPHA = 2.8f;  
  34.     /** 
  35.      * 自动回滚到中间的速度 
  36.      */  
  37.     public static final float SPEED = 2;  
  38.   
  39.     private List<String> mDataList;  
  40.     /** 
  41.      * 选中的位置,这个位置是mDataList的中心位置,一直不变 
  42.      */  
  43.     private int mCurrentSelected;  
  44.     private Paint mPaint;  
  45.   
  46.     private float mMaxTextSize = 80;  
  47.     private float mMinTextSize = 40;  
  48.   
  49.     private float mMaxTextAlpha = 255;  
  50.     private float mMinTextAlpha = 120;  
  51.   
  52.     private int mColorText = 0x333333;  
  53.   
  54.     private int mViewHeight;  
  55.     private int mViewWidth;  
  56.   
  57.     private float mLastDownY;  
  58.     /** 
  59.      * 滑动的距离 
  60.      */  
  61.     private float mMoveLen = 0;  
  62.     private boolean isInit = false;  
  63.     private onSelectListener mSelectListener;  
  64.     private Timer timer;  
  65.     private MyTimerTask mTask;  
  66.   
  67.     Handler updateHandler = new Handler()  
  68.     {  
  69.   
  70.         @Override  
  71.         public void handleMessage(Message msg)  
  72.         {  
  73.             if (Math.abs(mMoveLen) < SPEED)  
  74.             {  
  75.                 mMoveLen = 0;  
  76.                 if (mTask != null)  
  77.                 {  
  78.                     mTask.cancel();  
  79.                     mTask = null;  
  80.                     performSelect();  
  81.                 }  
  82.             } else  
  83.                 // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚  
  84.                 mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;  
  85.             invalidate();  
  86.         }  
  87.   
  88.     };  
  89.   
  90.     public PickerView(Context context)  
  91.     {  
  92.         super(context);  
  93.         init();  
  94.     }  
  95.   
  96.     public PickerView(Context context, AttributeSet attrs)  
  97.     {  
  98.         super(context, attrs);  
  99.         init();  
  100.     }  
  101.   
  102.     public void setOnSelectListener(onSelectListener listener)  
  103.     {  
  104.         mSelectListener = listener;  
  105.     }  
  106.   
  107.     private void performSelect()  
  108.     {  
  109.         if (mSelectListener != null)  
  110.             mSelectListener.onSelect(mDataList.get(mCurrentSelected));  
  111.     }  
  112.   
  113.     public void setData(List<String> datas)  
  114.     {  
  115.         mDataList = datas;  
  116.         mCurrentSelected = datas.size() / 2;  
  117.         invalidate();  
  118.     }  
  119.   
  120.     public void setSelected(int selected)  
  121.     {  
  122.         mCurrentSelected = selected;  
  123.     }  
  124.   
  125.     private void moveHeadToTail()  
  126.     {  
  127.         String head = mDataList.get(0);  
  128.         mDataList.remove(0);  
  129.         mDataList.add(head);  
  130.     }  
  131.   
  132.     private void moveTailToHead()  
  133.     {  
  134.         String tail = mDataList.get(mDataList.size() - 1);  
  135.         mDataList.remove(mDataList.size() - 1);  
  136.         mDataList.add(0, tail);  
  137.     }  
  138.   
  139.     @Override  
  140.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
  141.     {  
  142.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  143.         mViewHeight = getMeasuredHeight();  
  144.         mViewWidth = getMeasuredWidth();  
  145.         // 按照View的高度计算字体大小  
  146.         mMaxTextSize = mViewHeight / 4.0f;  
  147.         mMinTextSize = mMaxTextSize / 2f;  
  148.         isInit = true;  
  149.         invalidate();  
  150.     }  
  151.   
  152.     private void init()  
  153.     {  
  154.         timer = new Timer();  
  155.         mDataList = new ArrayList<String>();  
  156.         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  157.         mPaint.setStyle(Style.FILL);  
  158.         mPaint.setTextAlign(Align.CENTER);  
  159.         mPaint.setColor(mColorText);  
  160.     }  
  161.   
  162.     @Override  
  163.     protected void onDraw(Canvas canvas)  
  164.     {  
  165.         super.onDraw(canvas);  
  166.         // 根据index绘制view  
  167.         if (isInit)  
  168.             drawData(canvas);  
  169.     }  
  170.   
  171.     private void drawData(Canvas canvas)  
  172.     {  
  173.         // 先绘制选中的text再往上往下绘制其余的text  
  174.         float scale = parabola(mViewHeight / 4.0f, mMoveLen);  
  175.         float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;  
  176.         mPaint.setTextSize(size);  
  177.         mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));  
  178.         // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标  
  179.         float x = (float) (mViewWidth / 2.0);  
  180.         float y = (float) (mViewHeight / 2.0 + mMoveLen);  
  181.         FontMetricsInt fmi = mPaint.getFontMetricsInt();  
  182.         float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));  
  183.   
  184.         canvas.drawText(mDataList.get(mCurrentSelected), x, baseline, mPaint);  
  185.         // 绘制上方data  
  186.         for (int i = 1; (mCurrentSelected - i) >= 0; i++)  
  187.         {  
  188.             drawOtherText(canvas, i, -1);  
  189.         }  
  190.         // 绘制下方data  
  191.         for (int i = 1; (mCurrentSelected + i) < mDataList.size(); i++)  
  192.         {  
  193.             drawOtherText(canvas, i, 1);  
  194.         }  
  195.   
  196.     }  
  197.   
  198.     /** 
  199.      * @param canvas 
  200.      * @param position 
  201.      *            距离mCurrentSelected的差值 
  202.      * @param type 
  203.      *            1表示向下绘制,-1表示向上绘制 
  204.      */  
  205.     private void drawOtherText(Canvas canvas, int position, int type)  
  206.     {  
  207.         float d = (float) (MARGIN_ALPHA * mMinTextSize * position + type  
  208.                 * mMoveLen);  
  209.         float scale = parabola(mViewHeight / 4.0f, d);  
  210.         float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;  
  211.         mPaint.setTextSize(size);  
  212.         mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));  
  213.         float y = (float) (mViewHeight / 2.0 + type * d);  
  214.         FontMetricsInt fmi = mPaint.getFontMetricsInt();  
  215.         float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));  
  216.         canvas.drawText(mDataList.get(mCurrentSelected + type * position),  
  217.                 (float) (mViewWidth / 2.0), baseline, mPaint);  
  218.     }  
  219.   
  220.     /** 
  221.      * 抛物线 
  222.      *  
  223.      * @param zero 
  224.      *            零点坐标 
  225.      * @param x 
  226.      *            偏移量 
  227.      * @return scale 
  228.      */  
  229.     private float parabola(float zero, float x)  
  230.     {  
  231.         float f = (float) (1 - Math.pow(x / zero, 2));  
  232.         return f < 0 ? 0 : f;  
  233.     }  
  234.   
  235.     @Override  
  236.     public boolean onTouchEvent(MotionEvent event)  
  237.     {  
  238.         switch (event.getActionMasked())  
  239.         {  
  240.         case MotionEvent.ACTION_DOWN:  
  241.             doDown(event);  
  242.             break;  
  243.         case MotionEvent.ACTION_MOVE:  
  244.             doMove(event);  
  245.             break;  
  246.         case MotionEvent.ACTION_UP:  
  247.             doUp(event);  
  248.             break;  
  249.         }  
  250.         return true;  
  251.     }  
  252.   
  253.     private void doDown(MotionEvent event)  
  254.     {  
  255.         if (mTask != null)  
  256.         {  
  257.             mTask.cancel();  
  258.             mTask = null;  
  259.         }  
  260.         mLastDownY = event.getY();  
  261.     }  
  262.   
  263.     private void doMove(MotionEvent event)  
  264.     {  
  265.   
  266.         mMoveLen += (event.getY() - mLastDownY);  
  267.   
  268.         if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2)  
  269.         {  
  270.             // 往下滑超过离开距离  
  271.             moveTailToHead();  
  272.             mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;  
  273.         } else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2)  
  274.         {  
  275.             // 往上滑超过离开距离  
  276.             moveHeadToTail();  
  277.             mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;  
  278.         }  
  279.   
  280.         mLastDownY = event.getY();  
  281.         invalidate();  
  282.     }  
  283.   
  284.     private void doUp(MotionEvent event)  
  285.     {  
  286.         // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置  
  287.         if (Math.abs(mMoveLen) < 0.0001)  
  288.         {  
  289.             mMoveLen = 0;  
  290.             return;  
  291.         }  
  292.         if (mTask != null)  
  293.         {  
  294.             mTask.cancel();  
  295.             mTask = null;  
  296.         }  
  297.         mTask = new MyTimerTask(updateHandler);  
  298.         timer.schedule(mTask, 0, 10);  
  299.     }  
  300.   
  301.     class MyTimerTask extends TimerTask  
  302.     {  
  303.         Handler handler;  
  304.   
  305.         public MyTimerTask(Handler handler)  
  306.         {  
  307.             this.handler = handler;  
  308.         }  
  309.   
  310.         @Override  
  311.         public void run()  
  312.         {  
  313.             handler.sendMessage(handler.obtainMessage());  
  314.         }  
  315.   
  316.     }  
  317.   
  318.     public interface onSelectListener  
  319.     {  
  320.         void onSelect(String text);  
  321.     }  
  322. }  
package com.jingchen.timerpicker;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 滚动选择器
 * 
 * @author chenjing
 * 
 */
public class PickerView extends View
{

	public static final String TAG = "PickerView";
	/**
	 * text之间间距和minTextSize之比
	 */
	public static final float MARGIN_ALPHA = 2.8f;
	/**
	 * 自动回滚到中间的速度
	 */
	public static final float SPEED = 2;

	private List<String> mDataList;
	/**
	 * 选中的位置,这个位置是mDataList的中心位置,一直不变
	 */
	private int mCurrentSelected;
	private Paint mPaint;

	private float mMaxTextSize = 80;
	private float mMinTextSize = 40;

	private float mMaxTextAlpha = 255;
	private float mMinTextAlpha = 120;

	private int mColorText = 0x333333;

	private int mViewHeight;
	private int mViewWidth;

	private float mLastDownY;
	/**
	 * 滑动的距离
	 */
	private float mMoveLen = 0;
	private boolean isInit = false;
	private onSelectListener mSelectListener;
	private Timer timer;
	private MyTimerTask mTask;

	Handler updateHandler = new Handler()
	{

		@Override
		public void handleMessage(Message msg)
		{
			if (Math.abs(mMoveLen) < SPEED)
			{
				mMoveLen = 0;
				if (mTask != null)
				{
					mTask.cancel();
					mTask = null;
					performSelect();
				}
			} else
				// 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚
				mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;
			invalidate();
		}

	};

	public PickerView(Context context)
	{
		super(context);
		init();
	}

	public PickerView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		init();
	}

	public void setOnSelectListener(onSelectListener listener)
	{
		mSelectListener = listener;
	}

	private void performSelect()
	{
		if (mSelectListener != null)
			mSelectListener.onSelect(mDataList.get(mCurrentSelected));
	}

	public void setData(List<String> datas)
	{
		mDataList = datas;
		mCurrentSelected = datas.size() / 2;
		invalidate();
	}

	public void setSelected(int selected)
	{
		mCurrentSelected = selected;
	}

	private void moveHeadToTail()
	{
		String head = mDataList.get(0);
		mDataList.remove(0);
		mDataList.add(head);
	}

	private void moveTailToHead()
	{
		String tail = mDataList.get(mDataList.size() - 1);
		mDataList.remove(mDataList.size() - 1);
		mDataList.add(0, tail);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mViewHeight = getMeasuredHeight();
		mViewWidth = getMeasuredWidth();
		// 按照View的高度计算字体大小
		mMaxTextSize = mViewHeight / 4.0f;
		mMinTextSize = mMaxTextSize / 2f;
		isInit = true;
		invalidate();
	}

	private void init()
	{
		timer = new Timer();
		mDataList = new ArrayList<String>();
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setStyle(Style.FILL);
		mPaint.setTextAlign(Align.CENTER);
		mPaint.setColor(mColorText);
	}

	@Override
	protected void onDraw(Canvas canvas)
	{
		super.onDraw(canvas);
		// 根据index绘制view
		if (isInit)
			drawData(canvas);
	}

	private void drawData(Canvas canvas)
	{
		// 先绘制选中的text再往上往下绘制其余的text
		float scale = parabola(mViewHeight / 4.0f, mMoveLen);
		float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
		mPaint.setTextSize(size);
		mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
		// text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标
		float x = (float) (mViewWidth / 2.0);
		float y = (float) (mViewHeight / 2.0 + mMoveLen);
		FontMetricsInt fmi = mPaint.getFontMetricsInt();
		float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));

		canvas.drawText(mDataList.get(mCurrentSelected), x, baseline, mPaint);
		// 绘制上方data
		for (int i = 1; (mCurrentSelected - i) >= 0; i++)
		{
			drawOtherText(canvas, i, -1);
		}
		// 绘制下方data
		for (int i = 1; (mCurrentSelected + i) < mDataList.size(); i++)
		{
			drawOtherText(canvas, i, 1);
		}

	}

	/**
	 * @param canvas
	 * @param position
	 *            距离mCurrentSelected的差值
	 * @param type
	 *            1表示向下绘制,-1表示向上绘制
	 */
	private void drawOtherText(Canvas canvas, int position, int type)
	{
		float d = (float) (MARGIN_ALPHA * mMinTextSize * position + type
				* mMoveLen);
		float scale = parabola(mViewHeight / 4.0f, d);
		float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
		mPaint.setTextSize(size);
		mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
		float y = (float) (mViewHeight / 2.0 + type * d);
		FontMetricsInt fmi = mPaint.getFontMetricsInt();
		float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
		canvas.drawText(mDataList.get(mCurrentSelected + type * position),
				(float) (mViewWidth / 2.0), baseline, mPaint);
	}

	/**
	 * 抛物线
	 * 
	 * @param zero
	 *            零点坐标
	 * @param x
	 *            偏移量
	 * @return scale
	 */
	private float parabola(float zero, float x)
	{
		float f = (float) (1 - Math.pow(x / zero, 2));
		return f < 0 ? 0 : f;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		switch (event.getActionMasked())
		{
		case MotionEvent.ACTION_DOWN:
			doDown(event);
			break;
		case MotionEvent.ACTION_MOVE:
			doMove(event);
			break;
		case MotionEvent.ACTION_UP:
			doUp(event);
			break;
		}
		return true;
	}

	private void doDown(MotionEvent event)
	{
		if (mTask != null)
		{
			mTask.cancel();
			mTask = null;
		}
		mLastDownY = event.getY();
	}

	private void doMove(MotionEvent event)
	{

		mMoveLen += (event.getY() - mLastDownY);

		if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2)
		{
			// 往下滑超过离开距离
			moveTailToHead();
			mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;
		} else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2)
		{
			// 往上滑超过离开距离
			moveHeadToTail();
			mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;
		}

		mLastDownY = event.getY();
		invalidate();
	}

	private void doUp(MotionEvent event)
	{
		// 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置
		if (Math.abs(mMoveLen) < 0.0001)
		{
			mMoveLen = 0;
			return;
		}
		if (mTask != null)
		{
			mTask.cancel();
			mTask = null;
		}
		mTask = new MyTimerTask(updateHandler);
		timer.schedule(mTask, 0, 10);
	}

	class MyTimerTask extends TimerTask
	{
		Handler handler;

		public MyTimerTask(Handler handler)
		{
			this.handler = handler;
		}

		@Override
		public void run()
		{
			handler.sendMessage(handler.obtainMessage());
		}

	}

	public interface onSelectListener
	{
		void onSelect(String text);
	}
}

 

 

代码里的注释都写的很清楚了。接下来,我们就用写好的PickerView实现文章开头的图片效果吧~

首先看MainActivity的布局:

 

[html] view plain copy print?

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:background="#000000" >  
  5.   
  6.     <RelativeLayout  
  7.         android:layout_width="wrap_content"  
  8.         android:layout_height="wrap_content"  
  9.         android:layout_centerInParent="true"  
  10.         android:background="#ffffff" >  
  11.   
  12.         <com.jingchen.timerpicker.PickerView  
  13.             android:id="@+id/minute_pv"  
  14.             android:layout_width="80dp"  
  15.             android:layout_height="160dp" />  
  16.   
  17.         <TextView  
  18.             android:id="@+id/minute_tv"  
  19.             android:layout_width="wrap_content"  
  20.             android:layout_height="wrap_content"  
  21.             android:layout_centerVertical="true"  
  22.             android:layout_toRightOf="@id/minute_pv"  
  23.             android:text="分"  
  24.             android:textColor="#ffaa33"  
  25.             android:textSize="26sp"  
  26.             android:textStyle="bold" />  
  27.   
  28.         <com.jingchen.timerpicker.PickerView  
  29.             android:id="@+id/second_pv"  
  30.             android:layout_width="80dp"  
  31.             android:layout_height="160dp"  
  32.             android:layout_toRightOf="@id/minute_tv" />  
  33.   
  34.         <TextView  
  35.             android:id="@+id/second_tv"  
  36.             android:layout_width="wrap_content"  
  37.             android:layout_height="wrap_content"  
  38.             android:layout_centerVertical="true"  
  39.             android:layout_toRightOf="@id/second_pv"  
  40.             android:text="秒"  
  41.             android:textColor="#ffaa33"  
  42.             android:textSize="26sp"  
  43.             android:textStyle="bold" />  
  44.     </RelativeLayout>  
  45.   
  46. </RelativeLayout>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000" >

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="#ffffff" >

        <com.jingchen.timerpicker.PickerView
            android:id="@+id/minute_pv"
            android:layout_width="80dp"
            android:layout_height="160dp" />

        <TextView
            android:id="@+id/minute_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@id/minute_pv"
            android:text="分"
            android:textColor="#ffaa33"
            android:textSize="26sp"
            android:textStyle="bold" />

        <com.jingchen.timerpicker.PickerView
            android:id="@+id/second_pv"
            android:layout_width="80dp"
            android:layout_height="160dp"
            android:layout_toRightOf="@id/minute_tv" />

        <TextView
            android:id="@+id/second_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@id/second_pv"
            android:text="秒"
            android:textColor="#ffaa33"
            android:textSize="26sp"
            android:textStyle="bold" />
    </RelativeLayout>

</RelativeLayout>

两个PickerView两个TextView,很简单。

 

下面是MainActivity的代码:

 

[java] view plain copy print?

  1. package com.jingchen.timerpicker;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import com.jingchen.timerpicker.PickerView.onSelectListener;  
  7.   
  8. import android.app.Activity;  
  9. import android.os.Bundle;  
  10. import android.view.Menu;  
  11. import android.widget.TextView;  
  12. import android.widget.Toast;  
  13.   
  14. public class MainActivity extends Activity  
  15. {  
  16.   
  17.     PickerView minute_pv;  
  18.     PickerView second_pv;  
  19.   
  20.     @Override  
  21.     protected void onCreate(Bundle savedInstanceState)  
  22.     {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(R.layout.activity_main);  
  25.         minute_pv = (PickerView) findViewById(R.id.minute_pv);  
  26.         second_pv = (PickerView) findViewById(R.id.second_pv);  
  27.         List<String> data = new ArrayList<String>();  
  28.         List<String> seconds = new ArrayList<String>();  
  29.         for (int i = 0; i < 10; i++)  
  30.         {  
  31.             data.add("0" + i);  
  32.         }  
  33.         for (int i = 0; i < 60; i++)  
  34.         {  
  35.             seconds.add(i < 10 ? "0" + i : "" + i);  
  36.         }  
  37.         minute_pv.setData(data);  
  38.         minute_pv.setOnSelectListener(new onSelectListener()  
  39.         {  
  40.   
  41.             @Override  
  42.             public void onSelect(String text)  
  43.             {  
  44.                 Toast.makeText(MainActivity.this, "选择了 " + text + " 分",  
  45.                         Toast.LENGTH_SHORT).show();  
  46.             }  
  47.         });  
  48.         second_pv.setData(seconds);  
  49.         second_pv.setOnSelectListener(new onSelectListener()  
  50.         {  
  51.   
  52.             @Override  
  53.             public void onSelect(String text)  
  54.             {  
  55.                 Toast.makeText(MainActivity.this, "选择了 " + text + " 秒",  
  56.                         Toast.LENGTH_SHORT).show();  
  57.             }  
  58.         });  
  59.     }  
  60.   
  61.     @Override  
  62.     public boolean onCreateOptionsMenu(Menu menu)  
  63.     {  
  64.         getMenuInflater().inflate(R.menu.main, menu);  
  65.         return true;  
  66.     }  
  67.   
  68. }  
package com.jingchen.timerpicker;

import java.util.ArrayList;
import java.util.List;

import com.jingchen.timerpicker.PickerView.onSelectListener;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity
{

	PickerView minute_pv;
	PickerView second_pv;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		minute_pv = (PickerView) findViewById(R.id.minute_pv);
		second_pv = (PickerView) findViewById(R.id.second_pv);
		List<String> data = new ArrayList<String>();
		List<String> seconds = new ArrayList<String>();
		for (int i = 0; i < 10; i++)
		{
			data.add("0" + i);
		}
		for (int i = 0; i < 60; i++)
		{
			seconds.add(i < 10 ? "0" + i : "" + i);
		}
		minute_pv.setData(data);
		minute_pv.setOnSelectListener(new onSelectListener()
		{

			@Override
			public void onSelect(String text)
			{
				Toast.makeText(MainActivity.this, "选择了 " + text + " 分",
						Toast.LENGTH_SHORT).show();
			}
		});
		second_pv.setData(seconds);
		second_pv.setOnSelectListener(new onSelectListener()
		{

			@Override
			public void onSelect(String text)
			{
				Toast.makeText(MainActivity.this, "选择了 " + text + " 秒",
						Toast.LENGTH_SHORT).show();
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}


OK了,自定义自己的TimerPicker就是这么简单~

 

源码下载

 

    

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
作者jaaksi,源码pickerview,一个非常好用的 Android PickerView 库,内部提供 3 种常用类型的 Picker,支持扩展自定义 Picker:TimePicker:时间选择器,支持聚合模式的时间选择器(合并 v1.x 的 MixedTimePicker)OptionPicker:联动选择器效果图  APKDemo App下载连接PickerView READMEPicker通过组装 PickerView 实现常用的 Picker 选择器。上面已经列举提供的 3 中常用的 Picker。BasePickerPicker 基类:封装了 TopBar,PickerView 容器,create and add PickerView 方法,Picker 弹窗等方法。 三种 Picker 都继承自 BasePicker,你也可以继承它扩展自己的 Picker。APIapidescriptionsetPickerBackgroundColor设置 picker 背景setPadding设置 PickerView 父容器 padding 单位:pxsetTag给 Picker 设置 tag,用于区分不同的 picker 等。用法同 View setTaggetRootLayout获取 PickerView 的父容器,创建 DefaultTopBar 时必须指定setOnPickerChooseListener设置 picker 取消,确定按钮监听。可用于拦截选中操作setTopBar设置自定义 TopBarsetInterceptor设置拦截器createPickerView创建 PickerViewgetPickerViews获取 Picker 中所有的 pickerview 集合addPicker将创建的 PickerView 添加到上面集合中,createPickerView 内部已调用该方法findPickerViewByTag通过 tag 找到对应的 PickerViewisScrolling是否滚动未停止。滚动未停止的时候,不响应 Picker 的取消,确定按键getPickerDialog获取 Picker 弹窗。可以在 new 之后设置 dialog 属性show显示 picker 弹窗对比 github 上最受欢迎的同类库 Android-PickerView ,本库将 TopBar 等通用相关逻辑封装在基类中,并提供代码中创建 PickerView 方法,不需要再依赖 xml。用户自定义 Picker 时,继承 BasePicker,只需要处理自己的逻辑即可,简单便捷。 而对 Android-PickerView 来说,实现自定义 Picker,依然需要处理 TopBar 等逻辑,造成大量重复代码。TopBarTopBar:TopBar 通过抽象接口 ITopBar 来管理,实现 Picker 与 TopBar 的解耦。提供默认实现 DefaultTopBar。可实现接口定制自己的 TopBar。   public interface ITopBar {      /**       * @return topbar view       */      View getTopBarView();      /**       * @return 取消按钮 view       */      View getBtnCancel();      /**       * @return 确定按钮 view       */      View getBtnConfirm();      /**       * @return title view       */      TextView getTitleView();    }DefaultTopBar APIapidescriptionsetDividerColor设置 topbar bottom line colorsetDividerHeight设置 bottom divider line heightgetDivider获取 TopBar bottom linegetTitleView获取 TopBar title viewInterceptor拦截器:用于在 pickerview 创建时拦截,设置 pickerview 的属性。Picker 内部并不提供对 PickerView 的设置方法,而是通过 Interceptor 实现。这种设计用来实现 PickerPickerView 的属性设置完美解耦。   private void init(){     mTimePicker.setInterceptor(new 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值