android–自訂控制項–wheel

來源:互聯網
上載者:User

前段時間美工設計了一個控制項,辛辛苦苦花了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;//臨時變數儲存觸摸前的offsetprivate 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() {@Overridepublic void scrollViewTouchStart(float y) {Log.e(TAG, "on touch start");mDragging = true;mStartTouchPos = y;mTouchInitialOffset = offset;mFlingVelocity = 0;}@Overridepublic void scrollViewTouchMove(float y) {Log.e(TAG, "on move");float dis = mStartTouchPos - y;setDirect(dis);offset = trap((int) (mTouchInitialOffset - dis));updateDisplay();}@Overridepublic void scrollViewTouchEnd() {Log.e(TAG, "on touch end");mDragging = false;//offsetGaol = offset;invalidate();isCenter = true;}@Overridepublic void scrollViewFling(float vY) {Log.e(TAG, "on fling");mDragging = false;//offsetGaol = offset;mFlingVelocity = (int) (-vY);updateDisplay();}@Overridepublic void scrollViewDraw() {Log.d(TAG, "on draw");if (isCenter) {updateDisplay();isCenter = false;} else if (mFlingVelocity != 0) {updateDisplay();}}@Overridepublic 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() {@Overridepublic 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;}@Overrideprotected 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);}@Overrideprotected 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);}@Overridepublic 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){}}

代碼寫的不好。。如果有什麼疑問的請指教。。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.