1. 程式人生 > >Android自定義時間選擇器或者WheelView

Android自定義時間選擇器或者WheelView

public class PickView 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 Paint mPaint2; private float mMaxTextSize = 20; private float mMinTextSize = 18; private float mMaxTextAlpha = 255; private float mMinTextAlpha = 120; // private int mColorText = 0x03ab40; // private int mColorText2 = 0x000000;
private int mColorText = 0xe7e4e6; private int mColorText2 = 0xd2c2c3; 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 PickView(Context context) { super(context); init(); } public PickView(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; // if(mCurrentSelected!=0){ // // } // 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(Paint.Style.FILL); mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setColor(mColorText); mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint2.setStyle(Paint.Style.FILL); mPaint2.setTextAlign(Paint.Align.CENTER); mPaint2.setColor(mColorText2); } @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; //Log.d("maxsize",size+"================"); mPaint.setTextSize(45); mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha)); // text居中繪製,注意baseline的計算才能達到居中,y值是text中心座標 float x = (float) (mViewWidth / 2.0); float y = (float) (mViewHeight / 2.0 + mMoveLen); Paint.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 + type * mMoveLen); float scale = parabola(mViewHeight / 4.0f, d); float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize; // Log.d("msize",size+"================"); mPaint2.setTextSize(35); mPaint2.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha)); float y = (float) (mViewHeight / 2.0 + type * d); Paint.FontMetricsInt fmi = mPaint2.getFontMetricsInt(); float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); canvas.drawText(mDataList.get(mCurrentSelected + type), (float) (mViewWidth / 2.0), baseline, mPaint2); } /** * 拋物線 * * @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); }

}

自定義view的使用:

xml:

   <LinearLayout
app:layout_heightPercent="81%h"
app:layout_widthPercent="48.1%w"
android:orientation="horizontal"
android:layout_centerInParent="true"
android:layout_width="0dp"
android:layout_height="0dp">
            <com.yosemite.myview.PickView
android:layout_alignParentLeft="true"
android:id="@+id/pickview_hour"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
            <com.yosemite.myview.PickView
android:layout_alignParentRight="true"
android:id="@+id/pickview_minute"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
/>

        </LinearLayout>

程式碼中:

pickview_hour= (PickView) findViewById(R.id.pickview_hour);
pickview_minute= (PickView) findViewById(R.id.pickview_minute);
pickview_minute.setSelected(30);
List hours=new ArrayList(); List minutes=new ArrayList();

for (int i = 0; i < 24; i++)
{
    hours.add(i < 10 ? "0" + i : "" + i);
}
for (int i = 0; i < 60; i++)
{
    minutes.add(i < 10 ? "0" + i : "" + i);
}
pickview_hour.setData(hours);
pickview_hour.setSelected(12);
pickview_minute.setData(minutes);
pickview_minute.setOnSelectListener(new PickView.onSelectListener() {
    @Override
public void onSelect(String text) {

    }
});

相關推薦

Android定義時間選擇或者WheelView

public class PickView extends View{ public static final String TAG = "PickerView"; /** * text之間間距和minTextSize之比 */ publ

定義時間選擇(更改分割線和距離)

一、首先了解DatePicker原始碼的佈局        年、月、日 是由3個numberPicker組成  通過發射獲取到NumberPicker 如果不想顯示天數 ,重新佈局       lps.wid

Android 定義數字選擇,可以根據自己的需求更改

實現效果如下: 還是以往的套路,先把那些專案所需要的給展示出來。 values下的資料夾,attrs.xml <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styl

定義時間選擇UIPickerView

使用方法:@property (nonatomic, assign) QLChangeTimeView *chooseTimeView;//時間選擇檢視_chooseTimeView = [[NSBundle mainBundle]loadNibNamed:@"QLChangeTim

iOS 定義時間選擇 DatePicker

6種時間選擇方式: 年月日、年月日時、年月日時分、時分、日時分、月日時分 呼叫方式 [[DatePicker shareManager]showWithType:PickerTypeDay title:nil time:@"2018:10:31" backT

Android定義狀態選擇屬性

其實,android已經給我們提供了比較豐富的狀態選擇器屬性了,比如android:state_checked、android:state_pressed、android:state_selected、android:state_enabled等等,相信大家都不

Android基於wheelView定義日期選擇(可拓展樣式)

基於wheelView的自定義日期選擇器 專案要求效果圖: 要求 “6月20 星期五” 這一項作為一個整體可以滑動,”7時”、”48分”分別作為一個滑動整體。 系統自帶的DatePicker、TimePicker大家都知道,只有這種效果:

Android 仿 iphone 定義滾動選擇

背景:其實我們都知道,在我們做開發的過程中,會遇到Android 自身所帶控制元件不夠的情況,那麼這個時候,就需要我們自定義控制元件,所以,也就造成了,在開發的過程中,我們一定要掌握好自定義控制元件,不然,當你去一家公司,產品萌妹子過來找你,這個效果很不錯,問你能不能實

Android ListView三級聯動,實現定義地址選擇

說到地址選擇器,好多小夥伴第一印象就是——wheelView~這玩意確實挺好用的^(* ̄(oo) ̄)^! 然而悲劇的故事發生了,傲嬌的老闆不喜歡wheelView那種選中條不動的效果 ~(⊙o⊙)! 好吧,其實是老闆不知道從哪個忘記名字的App看到這種效果,

Android 定義自由選擇時間區間的日曆控制元件

摸滾打爬在Android界小菜鳥,突然靜下心想想自己都做過些什麼呢!留下些什麼呢!感覺自己老是copy別人的東西自己都不好意思了,於是今天就 來分享下自己最近寫專案中的一個自定義日曆控制元件 (翻閱了各大開源日曆都沒有合適的),希望大家多多指點,第一次寫部落格如果有不足之處

定義Jquery選擇

如果當前jQuery內建的選擇器不夠用,開發人員也可以擴充套件jQuery,實現使用者自定義的選擇器。 如下面建立一個具有綠色背景元素的選擇器。 <script> $(function(){ // 通過擴充套件$.expr[":"]實現自定義選擇器 $.expr[":

html+js定義顏色選擇

選擇 wid htm borde 效果圖 html () alt mage <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>test&

【舉例】Android定義Dialog——選擇一個RadioButton

1. 自定義Dialog的介面 <--!dialog_selectserver.xml--> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://sch

[Android開發基礎] 時間選擇

佈局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_w

Android定義視訊播放(網路/本地)

最近因公司專案要求需要寫一個播放器,自帶的又不太好用,也不太好看。自能自定義啦。查看了很多資料,都沒有完善的,還好得以為前輩的指點得以完成,感謝Yang。本篇裡面我有可能有些地方寫得不好(都附上了註釋)。希望各路大神指點,虛心受教。 先來個圖(原始碼在後面附上) 視訊列表裡面

Android原生的時間選擇——設定最低選擇年限

通過時間選擇器原始碼可以看到,如果不做任何設定,那麼最低許可權年是1900年,有的時候我們想設定自己的最低年限,比如說,設定最低時間為2000-01-01,程式碼如下: datePickerDialog.getDatePicker().setMinDate(),這個

android日期和時間選擇

今天簡要介紹一下日期和時間選擇器的使用 main.xml其實只有兩個按鈕,是日期和時間的選擇 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:to

安卓定義日曆選擇

哈哈,又要更新部落格了+_+! 這一次發一個日曆選擇器吧! 說實話,看到需求那一刻,我絕對是崩潰的,不過還好有github這個大佬罩著我,所以為了避免重複造輪子,我就去上面找了一下日曆選擇器,一搜一大把,剛開始挺高興的,結果後來越看臉越黑,沒一個符合我的需求

android 定義實現滾動View:WheelView

專案中用到一個比較覺得不錯的控制元件:WheelView,即上下滾動View。它是繼承ScrollView實現,在Android各版本上的效果都是如下:也許在git上有許多這樣功能的控制元件,但個人認為這個控制元件實現的方式簡單,比較讓人容易理解,對自定義控制元件的實現有借

Android 定義音樂播放實現

Android自定義音樂播放器一:首先介紹用了哪些Android的知識點:1 MediaPlayer工具來播放音樂2 Handle。因為存在定時任務(歌詞切換,動畫,歌詞進度條變換等)需要由Handle來處理Ui相關內容3 動態許可權申請(該應用程式讀取本地歌曲,並且設定音質