最近项目里要做个时间选择器,网上看了很多demo,自定义view学习很久了,自己打算做一个。.废话不多说,先了解下大概思路吧。首先要知道界面可滑动(这不废话吗),滑动到最大距离和最小距离自动弹回,滑动的总距离对item取余得到距离如果大于二分之一item则继续滑动剩余的长度,否则回弹到原来的位置;主要就是利用
Scroller和scrollby来是界面滑动,剩下就是一些距离计算和逻辑处理,看代码吧;有问题邮件给我965949332@qq.com
package com.calazova.club.guangzhu.widget; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.FontMetrics; import android.graphics.Paint.Style; import android.graphics.Rect; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.Scroller; import com.calazova.club.guangzhu.R; import java.util.ArrayList; import java.util.List; @SuppressLint("DrawAllocation") public class WheelView extends View { private Scroller scroller; private List<String> dataListItems = new ArrayList<String>(); private GestureDetector gestureDetector; private TypedArray obtainStyle; private float textsizeFefValue = 30; private float spacingmult = 15.0f;//调整这个大小可调整界面的高度 private float spacingadd = 2.0f; private int visibleItemNumber = 3;// 显示的个数从而决定view的高度 private int viewWidth = 0;// view宽度 private int touchSlop; private int flingVelocity; private float pulloff = 1.3f;// 阻尼系数 private int fontHeight;// 字体高度 private Paint textPaintItems; private Paint textPaintValues; private int currtPos;// 当前的item位置 private StringBuffer sb; private Context mContext; private Rect rect; public WheelView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } public WheelView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public WheelView(Context context) { super(context); } public void init(Context context, AttributeSet attrs) { mContext = context; scroller = new Scroller(context); gestureDetector = new GestureDetector(context, gestureListener); gestureDetector.setIsLongpressEnabled(false); obtainStyle = context.obtainStyledAttributes(attrs, R.styleable.wheelview); textsizeFefValue = obtainStyle.getDimension( R.styleable.wheelview_textsize, textsizeFefValue); obtainStyle.recycle(); getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { viewWidth = getWidth(); getViewTreeObserver() .removeGlobalOnLayoutListener(this); } }); ViewConfiguration config = ViewConfiguration.get(context); touchSlop = config.getScaledTouchSlop(); flingVelocity = config.getScaledMinimumFlingVelocity(); textPaintItems = new Paint(); textPaintItems.setColor(Color.parseColor("#ffffff")); textPaintItems.setStyle(Style.FILL); textPaintItems.setTextSize(textsizeFefValue); textPaintValues = new TextPaint(); textPaintValues.setColor(Color.parseColor("#76b347")); textPaintValues.setStyle(Style.FILL); textPaintValues.setTextSize(textsizeFefValue*1.3f); fontHeight = getFontHeight(textsizeFefValue, textPaintItems); sb = new StringBuffer(); rect = new Rect(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //drawCenterRect(canvas); if(dataListItems.size()>0){ // String message = sb.toString(); // staticLayoutValue = new StaticLayout(message, textPaint, canvas.getWidth(), // Alignment.ALIGN_CENTER, spacingmult, spacingadd, false); // staticLayoutValue.draw(canvas); // canvas.restore(); for (int i = 0; i < dataListItems.size(); i++) { FontMetrics fontMetrics = textPaintItems.getFontMetrics(); float fontTotalHeight = fontMetrics.bottom - fontMetrics.top; float offY = fontTotalHeight / 2 - fontMetrics.bottom; //float newY = baseY + offY; int scrollDistance = (int) ((i+1) *(spacingmult) + fontHeight*(2*i+1)/2+offY); if(i == currtPos){ textPaintValues.getTextBounds(dataListItems.get(currtPos), 0, 2, rect); int fontWidht = rect.width(); canvas.drawText(dataListItems.get(currtPos), getMeasuredWidth()/2-fontWidht/2, scrollDistance, textPaintValues); }else{ textPaintItems.getTextBounds(dataListItems.get(i), 0, 2, rect); int fontWidht = rect.width(); canvas.drawText(dataListItems.get(i), getMeasuredWidth()/2-fontWidht/2, scrollDistance, textPaintItems); } } } } private String slideTag = ""; private boolean isTouchFlag = false; private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() { public boolean onDown(MotionEvent e) { // isStopScroll = true; return true; }; public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { float y = e2.getY() - e1.getY(); isStopScroll=true; if (y > 0) { slideTag = "down"; scroll(distanceY); } else if (y < 0) { slideTag = "up"; scroll(distanceY); } return true; }; public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; }; }; private float totalDistance;// 可滑动的距离 private int scrollingOffset = 0; private int areaDetal;// 每次滑动的差值 private boolean flag =false; public void scroll(float scrollDistance) { scrollingOffset = (int) (scrollDistance / pulloff); scroller.startScroll(0, lastScrollY, 0, scrollingOffset - lastScrollY); invalidate(); } private int lastScrollY = 0; private int myLastScrollY = 0; @Override public void computeScroll() { super.computeScroll(); if (scroller.computeScrollOffset()) { if(isStopScroll){ isStopScroll=false; myLastScrollY = scroller.getFinalY(); scrollBy(0, scroller.getFinalY()); lastScrollY = getScrollY(); System.out.println("lastScrollY:"+lastScrollY); currtPos = (int)(lastScrollY/(fontHeight+spacingmult)+1); System.out.println("currtPos:"+currtPos); finishScroll(selectFlag); postInvalidate(); } } } private float startY = 0; @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { isStopScroll = true; jScroll(); //this.getParent().requestDisallowInterceptTouchEvent(false); return false; }else { this.getParent().requestDisallowInterceptTouchEvent(true); gestureDetector.onTouchEvent(event); } return true; }; private boolean isStopScroll = false; private int itemsHeight; //这个方法是最主要的 public void jScroll() { int myHeight = (int)(fontHeight+spacingmult); int halfItemsHeight = myHeight/2; int areaHeight = lastScrollY%myHeight;// 没有超过一个身位的高度 int scrollHeight=0;// 需要滚动的高度 int offet = 0;// if (Math.abs(areaHeight) >= halfItemsHeight) {// 多移动scrollHeight高度 scrollHeight = myHeight - Math.abs(areaHeight); } else { scrollHeight = Math.abs(areaHeight); } if(Math.abs(areaHeight) >= halfItemsHeight){ offet =scrollHeight; }else{ offet = -scrollHeight; } if(lastScrollY<=-myHeight){ currtPos = 0; scroller.startScroll(0, 0, 0, -lastScrollY-myHeight); }else if (lastScrollY>=totalDistance){ currtPos = dataListItems.size(); scroller.startScroll(0, 0, 0, (int)(-lastScrollY+totalDistance)); }else if(lastScrollY<=0&&lastScrollY>=-myHeight){ if(lastScrollY >= -halfItemsHeight){//一半的高度 scroller.startScroll(0, 0, 0, -lastScrollY); }else{ scroller.startScroll(0, 0, 0, -lastScrollY-myHeight); } }else{ scroller.startScroll(0, 0, 0, offet); } invalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int modeW = MeasureSpec.getMode(widthMeasureSpec); int sizeW = MeasureSpec.getSize(widthMeasureSpec); if (modeW == MeasureSpec.EXACTLY) { viewWidth = sizeW; } else { int myWidh = getPaddingLeft() + getPaddingRight() + viewWidth; if (modeW == MeasureSpec.AT_MOST) { viewWidth = Math.min(myWidh, modeW); } else { viewWidth = myWidh; } } float measuredHeight = (visibleItemNumber) * fontHeight + (visibleItemNumber+1) * spacingmult; itemsHeight = (int) (measuredHeight/3); setMeasuredDimension(viewWidth, (int) measuredHeight); } // 获取字体高度 public int getFontHeight(float fontSize, Paint paint) { paint.setTextSize(fontSize); FontMetrics fm = paint.getFontMetrics(); return (int) Math.ceil(fm.descent - fm.ascent); } /** * 设置item的显示的位置 * * @param listItems * 时间集合 * @param items * 显示的时间从几点开始 */ private int scrollTotalDistance = 0; private int getDefautY = 0; private int bytesize=0; public void setItem(List<String> listItems, String items) { dataListItems.addAll(listItems); for (int i = 0; i < dataListItems.size(); i++) { sb.append(dataListItems.get(i) + "\n"); } isStopScroll = true; currtPos = listItems.indexOf(items); // 默认中间显示的是第二个位置 int detalPos = currtPos-1; int scrollDistance = (int) (detalPos*(spacingmult+fontHeight)); int mysize = listItems.size()-2; totalDistance = (int) (mysize*(spacingmult+fontHeight)); scroller.startScroll(0, lastScrollY, 0, scrollDistance-lastScrollY); invalidate(); } public int getCurrtPos(){ return currtPos; } /** * */ public void limitArea(String mydata ){ int limitPos = dataListItems.indexOf(mydata); if(limitPos>=currtPos){ setAreaItem(mydata); } } LimitAreaListener limitAreaListener; public interface LimitAreaListener{ public void limitArea(); } public void addLimitAreaListener(LimitAreaListener limitAreaListener){ this.limitAreaListener = limitAreaListener; } public void finishScroll(boolean flag){ if(!flag){ try { if(limitAreaListener!=null){ limitAreaListener.limitArea(); } }catch (Exception e){ e.printStackTrace(); } } try { if(limitNoonistener!=null){ limitNoonistener.limitNoon(); } }catch (Exception e){ e.printStackTrace(); } } public void setAreaItem(String items){ isStopScroll = true; int limitPos = dataListItems.indexOf(items); int detalPos = limitPos-currtPos; int scrollDistance = (int)((detalPos)*(spacingmult+fontHeight)); if(scrollDistance == 0){ isStopScroll = false; } scroller.startScroll(0, 0, 0, scrollDistance); invalidate(); } boolean selectFlag = false; public void setSelectFlag(boolean selectFlag){ this.selectFlag = selectFlag; } LimitNoonistener limitNoonistener; public interface LimitNoonistener{ public void limitNoon(); } public void addLimitNoonistener(LimitNoonistener limitNoonistener){ this.limitNoonistener = limitNoonistener; }
}
在activit里边初始化
public void initWheelView(){
wheelview = (WheelView)findViewById(R.id.wheelview);for (int i=8;i<= 22;i++){ if(i<10){ listItemsTwo.add("0"+i); }else{ listItemsTwo.add(i+""); } } wheelview.setItem(listItemsTwo, "08");}通过wheelview.getCurrtPos()得到滑动的位置来取值; 主要的在jScroll()这个方法里;效果图: