1. 程式人生 > >自定義view單位的轉化、狀態儲存等

自定義view單位的轉化、狀態儲存等

自定義view單位的轉化

//dp轉px
int minWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120, 
getContext().getResources().getDisplayMetrics());

//sp轉px
int minHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 80, 
getContext().getResources().getDisplayMetrics());


 /**
     * 根據手機的解析度從 dp 的單位 轉成為 px(畫素)
     */
public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); }

工具類:

public class DensityUtils {  
    private DensityUtils() {  
        /* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated"); } public static int dp2px(Context context, float dpVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics()); } public
static int sp2px(Context context, float spVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, context.getResources().getDisplayMetrics()); } public static float px2dp(Context context, float pxVal) { final float scale = context.getResources().getDisplayMetrics().density; return (pxVal / scale); } public static float px2sp(Context context, float pxVal) { return (pxVal / context.getResources().getDisplayMetrics().scaledDensity); } }

自定義view狀態的儲存

  private static final String STATE_INSTANCE = "state_instance";
    private static final String STATE_TYPE = "state_type";
    private static final String STATE_BORDER_RADIUS = "state_border_radius";

    private int type;
    private int mBorderRadius;

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
        bundle.putInt(STATE_TYPE, type);
        bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            super.onRestoreInstanceState(((Bundle) state).getParcelable(STATE_INSTANCE));
            this.type = bundle.getInt(STATE_TYPE);
            this.mBorderRadius = bundle.getInt(STATE_BORDER_RADIUS);
        } else {
            super.onRestoreInstanceState(state);
        }
    }

自定義view的常用的onmeasure方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight()/2);
}

系統預設:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
          getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
  int result = size;
  int specMode = MeasureSpec.getMode(measureSpec);
  int specSize = MeasureSpec.getSize(measureSpec);

  switch (specMode) {
  case MeasureSpec.UNSPECIFIED:
      result = size;
      break;
  case MeasureSpec.AT_MOST:
  case MeasureSpec.EXACTLY:
      result = specSize;
      break;
  }
  return result;
}

系統預設wrap_content和match_parent效果一樣,測量寬高都是specSize,而這個specSize正是父控制元件剩餘的寬高,所以預設onMeasure方法中wrap_content 和match_parent 的效果是一樣的,都是填充剩餘的空間。

考慮wrap_content:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);   //獲取寬的模式
    int heightMode = MeasureSpec.getMode(heightMeasureSpec); //獲取高的模式
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);   //獲取寬的尺寸
    int heightSize = MeasureSpec.getSize(heightMeasureSpec); //獲取高的尺寸

    int width;
    int height ;
    if (widthMode == MeasureSpec.EXACTLY) {
        //如果match_parent或者具體的值,直接賦值
        width = widthSize;
    } else {
        //如果是wrap_content,我們要得到控制元件需要多大的尺寸
        float textWidth = mBound.width();   //文字的寬度
        //控制元件的寬度就是文字的寬度加上兩邊的內邊距。內邊距就是padding值,在構造方法執行完就被賦值
        width = (int) (getPaddingLeft() + textWidth + getPaddingRight());
    }
    //高度跟寬度處理方式一樣
    if (heightMode == MeasureSpec.EXACTLY) {
        height = heightSize;
    } else {
        float textHeight = mBound.height();
        height = (int) (getPaddingTop() + textHeight + getPaddingBottom());
    }

    //儲存測量寬度和測量高度
    setMeasuredDimension(width, height);
}

介面的定義示例:

    private OnLoadingCompleteListenter onLoadingCompleteListenter;

   interface OnLoadingCompleteListenter {
        void onComplete();
    }

    public OnLoadingCompleteListenter getOnLoadingCompleteListenter() {
        return onLoadingCompleteListenter;
    }

    public void setOnLoadingCompleteListenter(OnLoadingCompleteListenter onLoadingCompleteListenter) {
        this.onLoadingCompleteListenter = onLoadingCompleteListenter;
    }