现在的位置: 首页 > 综合 > 正文

android–自定义控件–wheel

2013年09月12日 ⁄ 综合 ⁄ 共 8005字 ⁄ 字号 评论关闭

前段时间美工设计了一个控件,辛辛苦苦花了2天才弄出来奋斗,结果偶然看到了网上原来有开源项目抓狂发火...

这个控件可以上下滚动,通过adapter可以拿到中间选中部分的值。。

先上个效果图先:

再上代码。。

这个是控件的view

注意哦:这个只是中间的白色的滚动部分和绿色部分的代码,周围的背景需要自己用xml布局。。图片啥的就不发了,毕竟是在公司做的。。。而且我上的图是用了2个这个控件排在一起的效果

public class ScrollListView extends View {
	public static final String TAG = ScrollListView.class.getSimpleName();
	
	static final int 			UP = 0;					//滑动方向,向上
	static final int 			DOWN = 1;				//滑动方向,向下
	
	private Context 			mContext;
	private GestureDetector 	mGestureDetector;
	
	private ScrollListViewAdapter<?> 	mData;
	private Paint 				mPaint;
	
	private int 				offset = 0;				// 偏移量,向上递减,向下递增
//	private int offsetGaol;
	private int 				mMaxPos;				//滑到最后一条元素的坐标
	private int 				mItemHeight = 50;		// 一行元素的高度
	private int 				mHalfItemHeight;		//半行元素的高度
	private int 				mHeight;				//绘制内容高度
	private int 				mHalfHeight;			//内容高度的一半
	private int 				mCurrentMiddleIndex;	//当前控件正中间的元素在list的索引值
	private int 				mFlingVelocity;			//fling的速度
	private int 				mTouchInitialOffset;	//临时变量保存触摸前的offset
	private boolean 			mDragging;				//是否在触摸状态
	private float 				mStartTouchPos;			//触摸起点坐标
	private float 				mTextOffsetY;			//字体居中偏移量
	private boolean 			isCenter = false;		// 让字居中的微调控制,为true进行调整,为false不进行调整
	private int 				mDirect = -1;			//方向
	
	private Bitmap mTop;
	private Bitmap mBottom;
	
	private float mTextPaddingLeft = 10;
	/**
	 * 控件触摸事件
	 * @author lhxia
	 *
	 */
	public interface ScrollViewListener {
		/**
		 * 触摸开始调用
		 * 
		 * @param y
		 *            触摸第一个点的Y坐标
		 */
		public void scrollViewTouchStart(float y);

		/**
		 * 触摸移动调用
		 * 
		 * @param y
		 *            当前触摸点的Y坐标
		 */
		public void scrollViewTouchMove(float y);

		/**
		 * 触摸完调用
		 */
		public void scrollViewTouchEnd();

		/**
		 * 当fling的时候调用
		 * 
		 * @param vY
		 *            Y方向坐标
		 */
		public void scrollViewFling(float vY);

		/**
		 * 更新控件
		 */
		public void scrollViewDraw();
		
		/**
		 * 速度为0时调用
		 */
		public void onStop(int index);
	};
	
	private ScrollViewListener mScrollViewListener = new ScrollViewListener() {

		@Override
		public void scrollViewTouchStart(float y) {
			Log.e(TAG, "on touch start");
			mDragging = true;
			mStartTouchPos = y;
			mTouchInitialOffset = offset;
			mFlingVelocity = 0;
		}

		@Override
		public void scrollViewTouchMove(float y) {
			Log.e(TAG, "on move");
			float dis = mStartTouchPos - y;
			setDirect(dis);
			offset = trap((int) (mTouchInitialOffset - dis));
			updateDisplay();
		}

		@Override
		public void scrollViewTouchEnd() {
			Log.e(TAG, "on touch end");
			mDragging = false;
//			offsetGaol = offset;
			invalidate();
			isCenter = true;
		}

		@Override
		public void scrollViewFling(float vY) {
			Log.e(TAG, "on fling");
			mDragging = false;
//			offsetGaol = offset;
			mFlingVelocity = (int) (-vY);
			updateDisplay();
		}

		@Override
		public void scrollViewDraw() {
			Log.d(TAG, "on draw");
			if (isCenter) {
				updateDisplay();
				isCenter = false;
			} else if (mFlingVelocity != 0) {
				updateDisplay();
			}
		}

		@Override
		public void onStop(int index) {
			if(mData != null){
				mData.onRefreshIndex(index);
			}
		}
	};
	
	/**
	 * 判断滑动方向
	 * @param dis 滑动距离
	 */
	private void setDirect(float dis) {
		if (dis > 0) {
			mDirect = UP;
		} else {
			mDirect = DOWN;
		}
	}

	/**
	 * 更新offset,并调用invalidate刷新界面
	 */
	private void updateDisplay() {
		if (!mDragging) {
			int offsetDelta = 0;
			if (mFlingVelocity != 0) {
				//速度不为0时,使控件减速
				Log.d(TAG, "speed down, v = " + mFlingVelocity);
				offsetDelta = mFlingVelocity / 40;
				// 速度递减
				if (mFlingVelocity > 90) {
					mFlingVelocity -= 90;
				} else if (mFlingVelocity < -90) {
					mFlingVelocity += 90;
				} else {
					mFlingVelocity = 0;
					Log.d(TAG, "stop, v = " + mFlingVelocity);
					isCenter = true;
				}

				offset -= offsetDelta;
				if (offset <= -(mMaxPos - (mHeight / 2) - mItemHeight)) {
					offset = -(mMaxPos - (mHeight / 2) - mItemHeight);
					mFlingVelocity = 0;
					isCenter = true;
					Log.d(TAG, "stop, v =  " + mFlingVelocity);
				}

				if (offset >= mHalfHeight) {
					offset = mHalfHeight;
					mFlingVelocity = 0;
					isCenter = true;
					Log.d(TAG, "stop, v = " + mFlingVelocity);
				}
//				offsetGaol = offset;
			} else {
				//当速度为0时,元素可能并没有居中,这里调整居中
				int delta = (mHalfHeight - offset) % mItemHeight;
				if (delta <= mHalfItemHeight - 10 && delta != 0) {
					delta += 1;
				} else if (delta > mHalfItemHeight + 10) {
					delta -= 1;
				} else {
					if (delta >= mHalfItemHeight) {
						delta += 1;
					} else if (delta < mHalfItemHeight) {
						delta -= 1;
					}
				}
				if (delta != 0) {
					isCenter = true;
				}
				if (mDirect == DOWN) {
					Log.d(TAG, "direct down");
					offset += delta;
				} else if (mDirect == UP) {
					Log.d(TAG, "direct up");
					offset += delta;
				}
				if(mScrollViewListener != null){
					mScrollViewListener.onStop(computeCurrentMiddlePosition());
				}
			}

		}
		invalidate();
	}

	/**
	 * 计算在数据的list中,当前显示在控件正中间的index
	 * 
	 * @return 当前控件中间的元素的索引
	 */
	private int computeCurrentMiddlePosition() {
		double f;
		if (offset <= 0) {
			f = ((-offset) + mHalfHeight) * 1.0 / mItemHeight;
		} else {
			f = (mHalfHeight - offset) * 1.0 / mItemHeight;
		}
		mCurrentMiddleIndex = (int) Math.round(f);
		if(mData != null){
			Log.d(TAG, "compute CurrentMiddlePosition is : "
					+ mCurrentMiddleIndex + "  size " + mData.size() + "  offset : " + offset + "\n"
					+ "halfheight" + mHalfHeight);
			
		}else {
			return -1;
		}
		return mCurrentMiddleIndex;
	}
	
	/**
	 * 检测offset的范围
	 * @param pos
	 * @return 返回检测后的offset
	 */
	private int trap(int pos) {
		if (pos >= mHeight / 2)
			return mHeight / 2;
		if (pos <= -(mMaxPos - (mHeight / 2) - mItemHeight))
			return -(mMaxPos - (mHeight / 2) - mItemHeight);
		return pos;
	}
	
	/**
	 * 获取当前中间的元素在list里面的index
	 * @return
	 */
	public int getMiddleIndex(){
		computeCurrentMiddlePosition();
		return mCurrentMiddleIndex;
	}
	
	/**
	 * 画9.png图片
	 * @param c canvas
	 * @param id 图片id
	 * @param r1 图片范围
	 */
	private void drawNinepath(Canvas c, int id, Rect r1) {
		Bitmap bmp = BitmapFactory.decodeResource(getResources(), id);

		NinePatch patch = new NinePatch(bmp, bmp.getNinePatchChunk(), null);
		patch.draw(c, r1);
	}

	public ScrollListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		mGestureDetector = new GestureDetector(context,
				new GestureDetector.SimpleOnGestureListener() {
					@Override
					public boolean onFling(MotionEvent e1, MotionEvent e2,
							float velocityX, float velocityY) {
						if (mScrollViewListener != null) {
							mScrollViewListener.scrollViewFling(velocityY);
						}
						return true;
					}

				});
		TypedArray type = context.obtainStyledAttributes(attrs,
		          R.styleable.ScrollListView);
	    int textColor = type.getColor(R.styleable.ScrollListView_textColor, 0XFF00FF00); //提供默认值,放置未指定     
	    float textSize = type.getDimension(R.styleable.ScrollListView_textSize, 25);   
	    mTextPaddingLeft =  type.getDimension(R.styleable.ScrollListView_paddingLeft, 25);   
	    type.recycle();
	    mPaint = new Paint();
	    mPaint.setAntiAlias(true);
		mPaint.setTextSize(textSize);
		mTextOffsetY = (mItemHeight - mPaint.getTextSize()) / 2;
		mPaint.setColor(textColor);
		mPaint.setTypeface(Typeface.SANS_SERIF);
		mTop = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bg_condition_top_alpha);
		mBottom = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bg_condition_bottom_alpha);
	}
	
	private void init(){
		if(mData != null){
			mMaxPos = mData.size() * mItemHeight;
		}
		offset = mHalfHeight;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		mHeight = MeasureSpec.getSize(heightMeasureSpec);
		mHalfHeight = mHeight / 2;
		mHalfItemHeight = mItemHeight / 2;
		offset = mHalfHeight;
//		offsetGaol = offset;
		computeCurrentMiddlePosition();
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// // 画中间线,用于调试
		// canvas.drawLine(0, mHalfHeight, getMeasuredWidth(), mHalfHeight,
		// mPaint);
		// canvas.drawLine(0, mHalfHeight - mItemHeight, getMeasuredWidth(),
		// mHalfHeight - mItemHeight, mPaint);
		float y = 0;
		if(mData != null){
			int size = mData.size();
			String tmp;
			for (int i = 0; i < size; i++) {
				y = i* mItemHeight + offset - mTextOffsetY + 20;
				tmp = mData.getValue(i);
				if(tmp != null && y > -20 || y < mHeight + 20){
					canvas.drawText(tmp, mTextPaddingLeft, i
							* mItemHeight + offset - mTextOffsetY + 20, mPaint);
				}
			}
			if (mScrollViewListener != null) {
				mScrollViewListener.scrollViewDraw();
			}
		}
		// canvas.drawLine(0, offset, getMeasuredWidth(), offset, mPaint);
		 drawNinepath(canvas, R.drawable.bg_condition_checked, new
		 Rect(0, (int)(mHalfHeight - mHalfItemHeight + 2), getMeasuredWidth(), (int)(mHalfHeight + mHalfItemHeight - 1)));
		//画2端渐变蒙版
//		drawNinepath(canvas, R.drawable.bg_condition_top_1,
//				new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight()));
		 canvas.drawBitmap(mTop, 0, 0, mPaint);
		 canvas.drawBitmap(mBottom, 0, mHeight - 4.3f, mPaint);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (mGestureDetector.onTouchEvent(event)) {
			return true;
		}

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mScrollViewListener.scrollViewTouchStart(event.getY());
			break;
		case MotionEvent.ACTION_MOVE:
			mScrollViewListener.scrollViewTouchMove(event.getY());
			break;
		case MotionEvent.ACTION_UP:
			mScrollViewListener.scrollViewTouchEnd();
			break;
		}
		return true;
	}

	public void setAdapter(ScrollListViewAdapter<?> adapter){
		mData = adapter;
		init();
		invalidate();
	}
	
	public ScrollListViewAdapter<?> getAdapter(){
		return mData;
	}
}

这个是adapter,用来把数据绑定到view上的:

public abstract class ScrollListViewAdapter<T> {
	
	public abstract String getValue(int index);
	
	public abstract int size();
	
	/**
	 * 当控件滚动的时候由控件调用
	 * @param index 索引
	 * @return
	 */
	public abstract int onRefreshIndex(int index);
	
	public abstract String getId(int index);
	
	public abstract T getItem(int index);
	
	public abstract void setList(List<T> data);
	
	public ScrollListViewAdapter(List<T> data){
		
	}
}

代码写的不好。。如果有什么疑问的请指教。。

抱歉!评论已关闭.