安卓实现滚动选择器

来源:互联网 发布:python shelve 编辑:程序博客网 时间:2024/05/19 11:39

转载请标明出处:http://blog.csdn.net/u011546655/article/details/45921025


背景:其实我们都知道,在我们做开发的过程中,会遇到Android 自身所带控件不够的情况,那么这个时候,就需要我们自定义控件,所以,也就造成了,在开发的过程中,我们一定要掌握好自定义控件,不然,当你去一家公司,产品萌妹子过来找你,这个效果很不错,问你能不能实现的时候,你难道能有理由说不行么,男人嘛,哪里能说不行了,直接用浑厚的声音告诉她,行,怎么不行,直接KO她。


一:多的不说,效果图,先走起





二:实例源码

(1)自定义控件

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



(2)实体类

[java] view plain copy
  1. package com.pickerscrollview.bean;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. /** 
  6.  *  
  7.  * @author zengtao 2015年5月20日下午7:18:14 
  8.  * 
  9.  */  
  10. public class Pickers implements Serializable {  
  11.   
  12.     private static final long serialVersionUID = 1L;  
  13.   
  14.     private String showConetnt;  
  15.     private String showId;  
  16.   
  17.     public String getShowConetnt() {  
  18.         return showConetnt;  
  19.     }  
  20.   
  21.     public String getShowId() {  
  22.         return showId;  
  23.     }  
  24.   
  25.     public Pickers(String showConetnt, String showId) {  
  26.         super();  
  27.         this.showConetnt = showConetnt;  
  28.         this.showId = showId;  
  29.     }  
  30.   
  31.     public Pickers() {  
  32.         super();  
  33.     }  
  34.   
  35. }  


(3)主界面

[java] view plain copy
  1. package com.pickerscrollview.ui;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.os.Bundle;  
  8. import android.view.View;  
  9. import android.view.View.OnClickListener;  
  10. import android.widget.Button;  
  11. import android.widget.RelativeLayout;  
  12.   
  13. import com.pickerscrollview.bean.Pickers;  
  14. import com.pickerscrollview.views.PickerScrollView;  
  15. import com.pickerscrollview.views.PickerScrollView.onSelectListener;  
  16.   
  17. /** 
  18.  * 主界面 
  19.  *  
  20.  * @author zengtao 2015年5月20日 下午7:36:03 
  21.  * 
  22.  */  
  23. public class MainActivity extends Activity {  
  24.   
  25.     private Button bt_scrollchoose; // 滚动选择器按钮  
  26.     private PickerScrollView pickerscrlllview; // 滚动选择器  
  27.     private List<Pickers> list; // 滚动选择器数据  
  28.     private String[] id;  
  29.     private String[] name;  
  30.   
  31.     private Button bt_yes; // 确定按钮  
  32.     private RelativeLayout picker_rel; // 选择器布局  
  33.   
  34.     @Override  
  35.     protected void onCreate(Bundle savedInstanceState) {  
  36.         super.onCreate(savedInstanceState);  
  37.         setContentView(R.layout.activity_main);  
  38.   
  39.         initView();  
  40.         initLinstener();  
  41.         initData();  
  42.     }  
  43.   
  44.     /** 
  45.      * 初始化 
  46.      */  
  47.     private void initView() {  
  48.         bt_scrollchoose = (Button) findViewById(R.id.bt_scrollchoose);  
  49.         picker_rel = (RelativeLayout) findViewById(R.id.picker_rel);  
  50.         pickerscrlllview = (PickerScrollView) findViewById(R.id.pickerscrlllview);  
  51.         bt_yes = (Button) findViewById(R.id.picker_yes);  
  52.     }  
  53.   
  54.     /** 
  55.      * 设置监听事件 
  56.      */  
  57.     private void initLinstener() {  
  58.         bt_scrollchoose.setOnClickListener(onClickListener);  
  59.         pickerscrlllview.setOnSelectListener(pickerListener);  
  60.         bt_yes.setOnClickListener(onClickListener);  
  61.     }  
  62.   
  63.     /** 
  64.      * 初始化数据 
  65.      */  
  66.     private void initData() {  
  67.         list = new ArrayList<Pickers>();  
  68.         id = new String[] { "1""2""3""4""5""6" };  
  69.         name = new String[] { "中国银行""农业银行""招商银行""工商银行""建设银行""民生银行" };  
  70.         for (int i = 0; i < name.length; i++) {  
  71.             list.add(new Pickers(name[i], id[i]));  
  72.         }  
  73.         // 设置数据,默认选择第一条  
  74.         pickerscrlllview.setData(list);  
  75.         pickerscrlllview.setSelected(0);  
  76.     }  
  77.   
  78.     // 滚动选择器选中事件  
  79.     onSelectListener pickerListener = new onSelectListener() {  
  80.   
  81.         @Override  
  82.         public void onSelect(Pickers pickers) {  
  83.             System.out.println("选择:" + pickers.getShowId() + "--银行:"  
  84.                     + pickers.getShowConetnt());  
  85.         }  
  86.     };  
  87.   
  88.     // 点击监听事件  
  89.     OnClickListener onClickListener = new OnClickListener() {  
  90.   
  91.         @Override  
  92.         public void onClick(View v) {  
  93.             if (v == bt_scrollchoose) {  
  94.                 picker_rel.setVisibility(View.VISIBLE);  
  95.             } else if (v == bt_yes) {  
  96.                 picker_rel.setVisibility(View.GONE);  
  97.             }  
  98.         }  
  99.     };  

  1. }  
Demo下载地址:http://download.csdn.net/detail/u011546655/8729407

原创粉丝点击