国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android滾輪選擇時間控件使用詳解

2019-12-12 04:21:23
字體:
供稿:網(wǎng)友

滾輪選擇控件

Android自帶的選擇時間控件有點丑,往往產(chǎn)品和設計都比較嫌棄,希望做成ios一樣的滾輪選擇,下面是我在NumberPicker的基礎上自定義的選擇控件,效果如下:

原理

  • 基于NumberPicker實現(xiàn)
  • 動態(tài)填充數(shù)值
  • 聯(lián)動
  • 接口監(jiān)聽回調(diào)

實現(xiàn)滾輪效果有github上mark比較多的WheelView,但是閱讀源碼發(fā)現(xiàn)數(shù)據(jù)是一次性填入的,選擇時間的話,填入10年就是10*365=3650條數(shù)據(jù),也就是new出三千多個TextView,想想都覺得恐怖,肯定是不行的,于是便想到用NumberPicker,動態(tài)填充數(shù)據(jù),一次只設置5個數(shù)據(jù),當選中變化時,重新設置數(shù)據(jù)填充,所以關鍵在于填充的數(shù)據(jù)的計算。

設置數(shù)據(jù)部分邏輯代碼:

  /**   * 更新左側(cè)控件   * 日期:選擇年控件   * 時間:選擇月份和日期控件   *   * @param timeMillis   */  private void updateLeftValue(long timeMillis) {    SimpleDateFormat sdf;    String str[] = new String[DATA_SIZE];    if (mCurrentType == TYPE_PICK_DATE) {      sdf = new SimpleDateFormat("yyyy");      for (int i = 0; i < DATA_SIZE; i++) {        Calendar cal = Calendar.getInstance();        cal.setTimeInMillis(timeMillis);        cal.add(Calendar.YEAR, (i - DATA_SIZE / 2));        str[i] = sdf.format(cal.getTimeInMillis());      }    } else {      sdf = new SimpleDateFormat("MM-dd EEE");      for (int i = 0; i < DATA_SIZE; i++) {        Calendar cal = Calendar.getInstance();        cal.setTimeInMillis(timeMillis);        cal.add(Calendar.DAY_OF_MONTH, (i - DATA_SIZE / 2));        str[i] = sdf.format(cal.getTimeInMillis());      }    }    mNpLeft.setDisplayedValues(str);    mNpLeft.setValue(DATA_SIZE / 2);    mNpLeft.postInvalidate();  }

對滾輪的監(jiān)聽,并重新設置填充數(shù)據(jù):

  @Override  public void onValueChange(NumberPicker picker, int oldVal, int newVal) {    Calendar calendar = Calendar.getInstance();    calendar.setTimeInMillis(mTimeMillis);    int year = calendar.get(Calendar.YEAR);    int month = calendar.get(Calendar.MONTH);    int day = calendar.get(Calendar.DAY_OF_MONTH);    int hour = calendar.get(Calendar.HOUR_OF_DAY);    int offset = newVal - oldVal;    if (picker == mNpLeft) {      if (mCurrentType == TYPE_PICK_DATE) {        calendar.add(Calendar.YEAR, offset);      } else {        calendar.add(Calendar.DAY_OF_MONTH, offset);      }      updateLeftValue(calendar.getTimeInMillis());      mTimeMillis = calendar.getTimeInMillis();    } else if (picker == mNpMiddle) {      if (mCurrentType == TYPE_PICK_DATE) {        calendar.add(Calendar.MONTH, offset);        if (calendar.get(Calendar.YEAR) != year) {          calendar.set(Calendar.YEAR, year);        }      } else {        calendar.add(Calendar.HOUR_OF_DAY, offset);        if (calendar.get(Calendar.DAY_OF_MONTH) != day) {          calendar.set(Calendar.DAY_OF_MONTH, day);        }        if (calendar.get(Calendar.MONTH) != month) {          calendar.set(Calendar.MONTH, month);        }        if (calendar.get(Calendar.YEAR) != year) {          calendar.set(Calendar.YEAR, year);        }      }      updateMiddleValue(calendar.getTimeInMillis());      updateRightValue(calendar.getTimeInMillis());      mTimeMillis = calendar.getTimeInMillis();    } else if (picker == mNpRight) {      if (mCurrentType == TYPE_PICK_DATE) {        int days = getMaxDayOfMonth(year, month + 1);        if(day == 1 && offset < 0){          calendar.set(Calendar.DAY_OF_MONTH,days);        }else if(day == days && offset > 0){          calendar.set(Calendar.DAY_OF_MONTH,1);        }else{          calendar.add(Calendar.DAY_OF_MONTH, offset);        }        if (calendar.get(Calendar.MONTH) != month) {          calendar.set(Calendar.MONTH, month);        }        if (calendar.get(Calendar.YEAR) != year) {          calendar.set(Calendar.YEAR, year);        }        Log.e(TAG,"time:::"+test.format(calendar.getTimeInMillis()));      } else {        calendar.add(Calendar.MINUTE, offset);        if (calendar.get(Calendar.HOUR_OF_DAY) != hour) {          calendar.set(Calendar.HOUR_OF_DAY, hour);        }        if (calendar.get(Calendar.DAY_OF_MONTH) != day) {          calendar.set(Calendar.DAY_OF_MONTH, day);        }        if (calendar.get(Calendar.MONTH) != month) {          calendar.set(Calendar.MONTH, month);        }        if (calendar.get(Calendar.YEAR) != year) {          calendar.set(Calendar.YEAR, year);        }      }      updateRightValue(calendar.getTimeInMillis());      mTimeMillis = calendar.getTimeInMillis();    }    /**     * 向外部發(fā)送當前選中時間     */    if (mOnSelectedChangeListener != null) {      mOnSelectedChangeListener.onSelected(this,mTimeMillis);    }    Log.e(TAG, "selected time:" + test.format(mTimeMillis));  }

選擇數(shù)值和字符串

同樣的,使用NumberPicker進行封裝,動態(tài)填充數(shù)值從而實現(xiàn)滾動變換的效果。

  • 考慮到通用性,傳入的是Object類型的數(shù)組,在控件里進行判斷。
  • 可以選擇一列數(shù)值、兩列數(shù)值、三列數(shù)值,字符串同理。每一列數(shù)值可以設置它的單位、標題等,默認是隱藏,需要自己設置。
  • 可以設置步長step

完整代碼如下:

package com.example.moore.picktimeview.widget;import android.content.Context;import android.graphics.Color;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.NumberPicker;import android.widget.TextView;/** * Created by Moore on 2016/10/21. */public class PickValueView extends LinearLayout implements NumberPicker.OnValueChangeListener {  private Context mContext;  /**   * 組件 標題、單位、滾輪   */  private TextView mTitleLeft, mTitleMiddle, mTitleRight;  private TextView mUnitLeft, mUnitMiddle, mUnitRight;  private MyNumberPicker mNpLeft, mNpMiddle, mNpRight;  /**   * 數(shù)據(jù)個數(shù) 1列 or 2列 or 3列   */  private int mViewCount = 1;  /**   * 一組數(shù)據(jù)長度   */  private final int DATA_SIZE = 3;  /**   * 需要設置的值與默認值   */  private Object[] mLeftValues;  private Object[] mMiddleValues;  private Object[] mRightValues;  private Object mDefaultLeftValue;  private Object mDefaultMiddleValue;  private Object mDefaultRightValue;  /**   * 當前正在顯示的值   */  private Object[] mShowingLeft = new Object[DATA_SIZE];  private Object[] mShowingMiddle = new Object[DATA_SIZE];  private Object[] mShowingRight = new Object[DATA_SIZE];  /**   * 步長   */  private int mLeftStep = 5;  private int mMiddleStep = 1;  private int mRightStep = 1;  /**   * 回調(diào)接口對象   */  private onSelectedChangeListener mSelectedChangeListener;  public PickValueView(Context context) {    super(context);    this.mContext = context;    generateView();  }  public PickValueView(Context context, AttributeSet attrs) {    super(context, attrs);    this.mContext = context;    generateView();  }  public PickValueView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    this.mContext = context;    generateView();  }  /**   * 生成視圖   */  private void generateView() {    //標題    LinearLayout titleLayout = new LinearLayout(mContext);    LayoutParams titleParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);    titleParams.setMargins(0, 0, 0, dip2px(12));    titleLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));    titleLayout.setOrientation(HORIZONTAL);    mTitleLeft = new TextView(mContext);    mTitleMiddle = new TextView(mContext);    mTitleRight = new TextView(mContext);    LayoutParams params = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);    TextView[] titles = new TextView[]{mTitleLeft, mTitleMiddle, mTitleRight};    for (int i = 0; i < titles.length; i++) {      titles[i].setLayoutParams(params);      titles[i].setGravity(Gravity.CENTER);      titles[i].setTextColor(Color.parseColor("#3434EE"));    }    titleLayout.addView(mTitleLeft);    titleLayout.addView(mTitleMiddle);    titleLayout.addView(mTitleRight);    //內(nèi)容    LinearLayout contentLayout = new LinearLayout(mContext);    contentLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));    contentLayout.setOrientation(HORIZONTAL);    contentLayout.setGravity(Gravity.CENTER);    mNpLeft = new MyNumberPicker(mContext);    mNpMiddle = new MyNumberPicker(mContext);    mNpRight = new MyNumberPicker(mContext);    mUnitLeft = new TextView(mContext);    mUnitMiddle = new TextView(mContext);    mUnitRight = new TextView(mContext);    MyNumberPicker[] nps = new MyNumberPicker[]{mNpLeft, mNpMiddle, mNpRight};    for (int i = 0; i < nps.length; i++) {      nps[i].setLayoutParams(params);      nps[i].setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);      nps[i].setOnValueChangedListener(this);    }    contentLayout.addView(mNpLeft);    contentLayout.addView(mUnitLeft);    contentLayout.addView(mNpMiddle);    contentLayout.addView(mUnitMiddle);    contentLayout.addView(mNpRight);    contentLayout.addView(mUnitRight);    this.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));    this.setOrientation(VERTICAL);    this.addView(titleLayout);    this.addView(contentLayout);  }  /**   * 初始化數(shù)據(jù)和值   */  private void initViewAndPicker() {    if (mViewCount == 1) {      this.mNpMiddle.setVisibility(GONE);      this.mNpRight.setVisibility(GONE);      this.mUnitMiddle.setVisibility(GONE);      this.mUnitRight.setVisibility(GONE);    } else if (mViewCount == 2) {      this.mNpRight.setVisibility(GONE);      this.mUnitRight.setVisibility(GONE);    }    //初始化數(shù)組值    if (mLeftValues != null && mLeftValues.length != 0) {      if (mLeftValues.length < DATA_SIZE) {        for (int i = 0; i < mLeftValues.length; i++) {          mShowingLeft[i] = mLeftValues[i];        }        for (int i = mLeftValues.length; i < DATA_SIZE; i++) {          mShowingLeft[i] = -9999;        }      } else {        for (int i = 0; i < DATA_SIZE; i++) {          mShowingLeft[i] = mLeftValues[i];        }      }      mNpLeft.setMinValue(0);      mNpLeft.setMaxValue(DATA_SIZE - 1);      if (mDefaultLeftValue != null)        updateLeftView(mDefaultLeftValue);      else        updateLeftView(mShowingLeft[0]);    }    /**     * 中間控件     */    if (mViewCount == 2 || mViewCount == 3) {      if (mMiddleValues != null && mMiddleValues.length != 0) {        if (mMiddleValues.length < DATA_SIZE) {          for (int i = 0; i < mMiddleValues.length; i++) {            mShowingMiddle[i] = mMiddleValues[i];          }          for (int i = mMiddleValues.length; i < DATA_SIZE; i++) {            mShowingMiddle[i] = -9999;          }        } else {          for (int i = 0; i < DATA_SIZE; i++) {            mShowingMiddle[i] = mMiddleValues[i];          }        }        mNpMiddle.setMinValue(0);        mNpMiddle.setMaxValue(DATA_SIZE - 1);        if (mDefaultMiddleValue != null)          updateMiddleView(mDefaultMiddleValue);        else          updateMiddleView(mShowingMiddle[0]);      }    }    /**     * 右側(cè)控件     */    if (mViewCount == 3) {      if (mRightValues != null && mRightValues.length != 0) {        if (mRightValues.length < DATA_SIZE) {          for (int i = 0; i < mRightValues.length; i++) {            mShowingRight[i] = mRightValues[i];          }          for (int i = mRightValues.length; i < DATA_SIZE; i++) {            mShowingRight[i] = -9999;          }        } else {          for (int i = 0; i < DATA_SIZE; i++) {            mShowingRight[i] = mRightValues[i];          }        }        mNpRight.setMinValue(0);        mNpRight.setMaxValue(DATA_SIZE - 1);        if (mDefaultRightValue != null)          updateRightView(mDefaultRightValue);        else          updateRightView(mShowingRight[0]);      }    }  }  private void updateLeftView(Object value) {    updateValue(value, 0);  }  private void updateMiddleView(Object value) {    updateValue(value, 1);  }  private void updateRightView(Object value) {    updateValue(value, 2);  }  /**   * 更新滾輪視圖   *   * @param value   * @param index   */  private void updateValue(Object value, int index) {    String showStr[] = new String[DATA_SIZE];    MyNumberPicker picker;    Object[] showingValue;    Object[] values;    int step;    if (index == 0) {      picker = mNpLeft;      showingValue = mShowingLeft;      values = mLeftValues;      step = mLeftStep;    } else if (index == 1) {      picker = mNpMiddle;      showingValue = mShowingMiddle;      values = mMiddleValues;      step = mMiddleStep;    } else {      picker = mNpRight;      showingValue = mShowingRight;      values = mRightValues;      step = mRightStep;    }    if (values instanceof Integer[]) {      for (int i = 0; i < DATA_SIZE; i++) {        showingValue[i] = (int) value - step * (DATA_SIZE / 2 - i);        int offset = (int) values[values.length - 1] - (int) values[0] + step;        if ((int) showingValue[i] < (int) values[0]) {          showingValue[i] = (int) showingValue[i] + offset;        }        if ((int) showingValue[i] > (int) values[values.length - 1]) {          showingValue[i] = (int) showingValue[i] - offset;        }        showStr[i] = "" + showingValue[i];      }    } else {      int strIndex = 0;      for (int i = 0; i < values.length; i++) {        if (values[i].equals(value)) {          strIndex = i;          break;        }      }      for (int i = 0; i < DATA_SIZE; i++) {        int temp = strIndex - (DATA_SIZE / 2 - i);        if (temp < 0) {          temp += values.length;        }        if (temp >= values.length) {          temp -= values.length;        }        showingValue[i] = values[temp];        showStr[i] = (String) values[temp];      }    }    picker.setDisplayedValues(showStr);    picker.setValue(DATA_SIZE / 2);    picker.postInvalidate();  }  @Override  public void onValueChange(NumberPicker picker, int oldVal, int newVal) {    if (picker == mNpLeft) {      updateLeftView(mShowingLeft[newVal]);    } else if (picker == mNpMiddle) {      updateMiddleView(mShowingMiddle[newVal]);    } else if (picker == mNpRight) {      updateRightView(mShowingRight[newVal]);    }    if (mSelectedChangeListener != null) {      mSelectedChangeListener.onSelected(this, mShowingLeft[DATA_SIZE / 2], mShowingMiddle[DATA_SIZE / 2], mShowingRight[DATA_SIZE / 2]);    }  }  /**   * 設置數(shù)據(jù)--單列數(shù)據(jù)   *   * @param leftValues   * @param mDefaultLeftValue   */  public void setValueData(Object[] leftValues, Object mDefaultLeftValue) {    this.mViewCount = 1;    this.mLeftValues = leftValues;    this.mDefaultLeftValue = mDefaultLeftValue;    initViewAndPicker();  }  /**   * 設置數(shù)據(jù)--兩列數(shù)據(jù)   *   * @param leftValues   * @param mDefaultLeftValue   * @param middleValues   * @param defaultMiddleValue   */  public void setValueData(Object[] leftValues, Object mDefaultLeftValue, Object[] middleValues, Object defaultMiddleValue) {    this.mViewCount = 2;    this.mLeftValues = leftValues;    this.mDefaultLeftValue = mDefaultLeftValue;    this.mMiddleValues = middleValues;    this.mDefaultMiddleValue = defaultMiddleValue;    initViewAndPicker();  }  /**   * 設置數(shù)據(jù)--三列數(shù)據(jù)   *   * @param leftValues   * @param mDefaultLeftValue   * @param middleValues   * @param defaultMiddleValue   * @param rightValues   * @param defaultRightValue   */  public void setValueData(Object[] leftValues, Object mDefaultLeftValue, Object[] middleValues, Object defaultMiddleValue, Object[] rightValues, Object defaultRightValue) {    this.mViewCount = 3;    this.mLeftValues = leftValues;    this.mDefaultLeftValue = mDefaultLeftValue;    this.mMiddleValues = middleValues;    this.mDefaultMiddleValue = defaultMiddleValue;    this.mRightValues = rightValues;    this.mDefaultRightValue = defaultRightValue;    initViewAndPicker();  }  /**   * 設置左邊數(shù)據(jù)步長   *   * @param step   */  public void setLeftStep(int step) {    this.mLeftStep = step;    initViewAndPicker();  }  /**   * 設置中間數(shù)據(jù)步長   *   * @param step   */  public void setMiddleStep(int step) {    this.mMiddleStep = step;    initViewAndPicker();  }  /**   * 設置右邊數(shù)據(jù)步長   *   * @param step   */  public void setRightStep(int step) {    this.mRightStep = step;    initViewAndPicker();  }  /**   * 設置標題   *   * @param left   * @param middle   * @param right   */  public void setTitle(String left, String middle, String right) {    if (left != null) {      mTitleLeft.setVisibility(VISIBLE);      mTitleLeft.setText(left);    } else {      mTitleLeft.setVisibility(GONE);    }    if (middle != null) {      mTitleMiddle.setVisibility(VISIBLE);      mTitleMiddle.setText(middle);    } else {      mTitleMiddle.setVisibility(GONE);    }    if (right != null) {      mTitleRight.setVisibility(VISIBLE);      mTitleRight.setText(right);    } else {      mTitleRight.setVisibility(GONE);    }    this.postInvalidate();  }  public void setUnitLeft(String unitLeft) {    setUnit(unitLeft, 0);  }  public void setmUnitMiddle(String unitMiddle) {    setUnit(unitMiddle, 1);  }  public void setUnitRight(String unitRight) {    setUnit(unitRight, 2);  }  private void setUnit(String unit, int index) {    TextView tvUnit;    if (index == 0) {      tvUnit = mUnitLeft;    } else if (index == 1) {      tvUnit = mUnitMiddle;    } else {      tvUnit = mUnitRight;    }    if (unit != null) {      tvUnit.setText(unit);    } else {      tvUnit.setText(" ");    }    initViewAndPicker();  }  /**   * 設置回調(diào)   *   * @param listener   */  public void setOnSelectedChangeListener(onSelectedChangeListener listener) {    this.mSelectedChangeListener = listener;  }  /**   * dp轉(zhuǎn)px   *   * @param dp   * @return   */  private int dip2px(int dp) {    float scale = mContext.getResources().getDisplayMetrics().density;    return (int) (scale * dp + 0.5f);  }  /**   * 回調(diào)接口   */  public interface onSelectedChangeListener {    void onSelected(PickValueView view, Object leftValue, Object middleValue, Object rightValue);  }}

關于NumberPicker

默認的NumberPicker往往字體顏色、分割線顏色等都是跟隨系統(tǒng),不能改變,考慮到可能比較丑或者有其他需求,所以自定義的NumberPicker,通過反射的方式更改里面的一些屬性,代碼如下:

package com.example.moore.picktimeview.widget;import android.content.Context;import android.graphics.Color;import android.graphics.drawable.ColorDrawable;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.view.ViewGroup;import android.widget.EditText;import android.widget.ImageButton;import android.widget.NumberPicker;import java.lang.reflect.Field;/** * Created by Moore on 2016/10/20. */public class MyNumberPicker extends NumberPicker {  private static int mTextSize = 16;  private static int mTextColor = 0x000000;  private static int mDividerColor = 0xFFFF00;  public MyNumberPicker(Context context) {    super(context);    setNumberPickerDividerColor();  }  public MyNumberPicker(Context context, AttributeSet attrs) {    super(context, attrs);    setNumberPickerDividerColor();  }  public MyNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    setNumberPickerDividerColor();  }  @Override  public void addView(View child) {    super.addView(child);    updateView(child);  }  @Override  public void addView(View child, int index, ViewGroup.LayoutParams params) {    super.addView(child, index, params);    updateView(child);  }  @Override  public void addView(View child, ViewGroup.LayoutParams params) {    super.addView(child, params);    updateView(child);  }  private void updateView(View view) {    if (view instanceof EditText) {//      ((EditText) view).setTextSize(mTextSize);      ((EditText) view).setTextSize(17);//      ((EditText) view).setTextColor(mTextColor);      ((EditText) view).setTextColor(Color.parseColor("#6495ED"));    }  }  private void setNumberPickerDividerColor() {    Field[] pickerFields = NumberPicker.class.getDeclaredFields();    /**     * 設置分割線顏色     */    for (Field pf : pickerFields) {      if (pf.getName().equals("mSelectionDivider")) {        pf.setAccessible(true);        try {//          pf.set(this, new ColorDrawable(mDividerColor));          pf.set(this, new ColorDrawable(Color.parseColor("#C4C4C4")));        } catch (IllegalAccessException e) {          e.printStackTrace();        }        break;      }    }    /**     * 設置分割線高度     */    for (Field pf : pickerFields) {      if (pf.getName().equals("mSelectionDividerHeight")) {        pf.setAccessible(true);        try {          pf.set(this, 2);        } catch (IllegalAccessException e) {          e.printStackTrace();        }        break;      }    }    for (Field pf : pickerFields) {      if (pf.getName().equals("mSelectorElementHeight")) {        pf.setAccessible(true);        try {          pf.set(this, 2);        } catch (IllegalAccessException e) {          e.printStackTrace();        }        break;      }    }  }  public void setDividerColor(int color) {    this.mDividerColor = color;//    this.postInvalidate();  }  public void setTextColor(int color) {    this.mTextColor = color;//    this.postInvalidate();  }  public void setTextSize(int textSize) {    this.mTextSize = textSize;//    this.postInvalidate();  }}

完整Demo可前往github查看與下載,地址:https://github.com/lizebinbin/PickTimeView.git 謝謝!

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 景宁| 德兴市| 恩平市| 乐陵市| 阿拉尔市| 乌恰县| 社会| 呼伦贝尔市| 寻甸| 建水县| 岑巩县| 陆河县| 淄博市| 鄂伦春自治旗| 杭州市| 万山特区| 永泰县| 浪卡子县| 东港市| 青阳县| 仁怀市| 榆树市| 包头市| 广丰县| 怀远县| 山东省| 南京市| 新乡市| 周宁县| 女性| 米林县| 滨海县| 临潭县| 赤壁市| 宁海县| 内黄县| 金溪县| 沂源县| 无锡市| 怀柔区| 加查县|