2013-11-28 47 views
5

創建自定義視圖,並將其加入到佈局:如何從自定義視圖中瞭解父級填充?

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:tools="http://schemas.android.com/tools" 
     xmlns:custom="http://schemas.android.com/apk/res/com.eleks.customview" 
     android:padding="20dp" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" > 

     <com.eleks.customview.CView 
      android:id="@+id/circle1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      custom:textSize="@dimen/circle_text_size" 
      custom:text="@string/circle_default_text" 
      custom:radius="@dimen/circle_radius" 
      custom:textColor="@color/circle_text" 
      custom:textBackground="@color/circle_background" /> 

    </LinearLayout> 

我實現自定義視圖onMeasure並設置寬度和高度。但我的觀點忽略父母填充(20dp)。看到圖片:

enter image description here

公共類CView的擴展視圖 { 私有靜態最後絃樂TAG = 「CView的」;

// default value 
private static final int DEFAULT_RADIUS = 30; 
private static final int DEFAULT_TEXT_SIZE = 12; 
private static final int DEFAULT_TEXT_COLOR = Color.BLACK; 
private static final int DEFAULT_BACKGROUND = Color.GRAY; 
private static final int DEFAULT_WIDTH = DEFAULT_RADIUS * 2; 
private static final int DEFAULT_HEIGHT = DEFAULT_RADIUS * 2; 

// variables 
private Paint mBackgroundPaint = null; 
private Paint mTextPaint = null; 
private float mCircleX = 0; 
private float mCircleY = 0; 
private float mTextX = 0; 
private float mTextY = 0; 
private int mWidth = DEFAULT_WIDTH; 
private int mHeight = DEFAULT_HEIGHT; 

// attrs 
private int mTextColor = DEFAULT_TEXT_COLOR; 
private int mBackground = DEFAULT_BACKGROUND; 
private float mRadius = DEFAULT_RADIUS; 
private String mText = null; 
private float mTextSize = 0; 

public CView(Context context) 
{ 
    super(context); 
    Log.d(TAG, "init view"); 
    init(null); 
} 

public CView(Context context, AttributeSet attrs) 
{ 
    super(context, attrs); 
    Log.d(TAG, "init view"); 
    init(attrs); 
} 

private void init(AttributeSet attrs) 
{ 
    if (attrs != null) 
    { 
     TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.CircleButton, 0, 0); 
     try 
     { 
      mTextColor = a.getColor(R.styleable.CircleButton_textColor, DEFAULT_TEXT_COLOR); 
      mBackground = a.getColor(R.styleable.CircleButton_textBackground, DEFAULT_BACKGROUND); 
      mRadius = a.getDimension(R.styleable.CircleButton_radius, DEFAULT_RADIUS); 
      mText = a.getString(R.styleable.CircleButton_text); 
      mTextSize = a.getDimensionPixelOffset(R.styleable.CircleButton_textSize, DEFAULT_TEXT_SIZE); 
     } 
     finally 
     { 
      a.recycle(); 
     } 
    } 
    mBackgroundPaint = new Paint(); 
    mBackgroundPaint.setColor(mBackground); 

    this.setMinimumHeight((int) mRadius * 2); 
    this.setMinimumWidth((int) mRadius * 2); 
} 

private void initLayoutParams() 
{ 
    LayoutParams params = this.getLayoutParams(); 
    params.width = mWidth + getLeft(); 
    params.height = mHeight + getTop(); 
    Log.d(TAG, "params| width: " + mWidth + " height: " + mHeight); 
} 

private void initText() 
{ 
    mTextPaint = new Paint(); 
    mTextPaint.setColor(mTextColor); 
    mTextPaint.setTextSize(mTextSize); 
    Rect textRect = new Rect(); 
    if (mText == null) 
    { 
     mText = ""; 
    } 
    mTextPaint.getTextBounds(mText, 0, mText.length(), textRect); 
    mTextX = mCircleX - (((Math.abs(textRect.right) - Math.abs(textRect.left)))/2); 
    mTextY = mRadius + ((Math.abs(textRect.top) - (Math.abs(textRect.bottom)))/2); 
    Log.d(TAG, "text| x: " + mTextX + " y: " + mTextY); 
} 

@Override 
protected void onDraw(Canvas canvas) 
{ 
    super.onDraw(canvas); 
    Log.d(TAG, "init onDraw"); 

    if (canvas != null) 
    { 
     canvas.drawCircle(mCircleX, mCircleY, mRadius, mBackgroundPaint); 
     // canvas.drawText(mText, mTextX, mTextY, mTextPaint); 
    } 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
{ 
    // super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    Log.d(TAG, "init onMeasure"); 
    setWidth(MeasureSpec.getMode(widthMeasureSpec), MeasureSpec.getSize(widthMeasureSpec)); 
    setHeight(MeasureSpec.getMode(heightMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); 
    mCircleX = getLeft() - getPaddingLeft() + mRadius; 
    mCircleY = getTop() - getPaddingTop() + mRadius; 
    fixedSize(); 
    Log.d(TAG, "circle| x: " + mCircleX + " y: " + mCircleY); 
    this.setMeasuredDimension(mWidth, mHeight); 
    // initText(); 

} 

private void fixedSize() 
{ 
    if (mWidth > mHeight) 
    { 
     mHeight = mWidth; 
    } 
    else if (mHeight > mWidth) 
    { 
     mWidth = mHeight; 
    } 
} 

private void setWidth(final int modeWidth, final int width) 
{ 
    switch (modeWidth) 
    { 
     case MeasureSpec.AT_MOST: 
      Log.d(TAG, "width mode is AT_MOST"); 
      if (mRadius > 0) 
      { 
       mWidth = (int) (mRadius * 2) + getPaddingLeft() + getPaddingRight(); 
      } 
      else 
      { 
       mWidth = DEFAULT_WIDTH; 
      } 
      mWidth = Math.min(mWidth, width); 
      break; 
     case MeasureSpec.EXACTLY: 
      Log.d(TAG, "width mode is EXACTLY"); 
      break; 
     case MeasureSpec.UNSPECIFIED: 
     default: 
      Log.d(TAG, "width mode is UNSPECIFIED"); 
      mWidth = DEFAULT_WIDTH; 
      break; 
    } 
} 

private void setHeight(final int modeHeight, final int height) 
{ 
    switch (modeHeight) 
    { 
     case MeasureSpec.AT_MOST: 
      Log.d(TAG, "height mode is AT_MOST"); 
      if (mRadius > 0) 
      { 
       mHeight = (int) (mRadius * 2) + getPaddingTop() + getPaddingBottom(); 
      } 
      else 
      { 
       mHeight = DEFAULT_HEIGHT; 
      } 
      mHeight = Math.min(mHeight, height); 
      break; 
     case MeasureSpec.EXACTLY: 
      Log.d(TAG, "height mode is EXACTLY"); 
      break; 
     case MeasureSpec.UNSPECIFIED: 
     default: 
      Log.d(TAG, "height mode is UNSPECIFIED"); 
      mHeight = DEFAULT_HEIGHT; 
      break; 
    } 
} 

@Override 
protected void onLayout(boolean changed, int left, int top, int right, int bottom) 
{ 
    // super.onLayout(changed, left, top, right, bottom); 
    Log.d(TAG, "init onLayout"); 
    initLayoutParams(); 
} 

我該如何獲得父母的填充?

+0

父母的填充將如何影響您的視圖? – pskink

+0

是的,家長的填充影響我的觀點。它的問題。 – Viacheslav

+0

所以我認爲你應該閱讀查看文檔,「大小,填充和邊距」部分 – pskink

回答

2

使用的getParent()但恕我直言,如果你需要它有一些設計缺陷

+0

檢查@Viacheslav評論問題的詳細答案 – Irfan

+0

@Irfan你是什麼意思?什麼意見? – pskink

+0

在對問題的評論中有一些詳細的解釋。我指的是這個。 – Irfan

0

父視圖的填充是由母公司來測量。你不應該考慮它。但是,您應該考慮到您的自定義小部件填充。該代碼不起作用,因爲你的措施沒有做它應該做的事。我沒有檢查代碼的其餘部分,但可能你也犯過其他錯誤)。

onMeasure()應該計算您的視圖的大小並將其設置爲setMeasuredDimension()

如果你想開發自定義視圖,你應該閱讀官方文檔。在這種情況下,onMeasure(int, int)方法文檔。我也建議閱讀關於how Android draw views

可能看看github上的一些小部件的代碼或一些標準的Android視圖,看他們如何衡量視圖。 (LinearLayout和RelativeLayout是很好的,非常不同,ViewGroups的例子),而ImageView是一個很好的Widget完整示例。

即使您沒有編寫ViewGroup查看它的工作方式,也有助於理解它對子視圖的期望。這個想法是,它可以(並且經常)是一個多步驟的過程,父母試圖通過傳遞不同的約束來讓孩子適應自己。

可以這樣想:measureSpecs(你收到的參數)告訴你是否應該取所有你想要的空間,如果你應該適合一個特定的尺寸或者確切的尺寸,無論是寬度還是寬度高度。您的小部件應該遵循這些約束,並使用您計算的任何度量調用setMeasuredDimension()

在你的情況下,它應該是2 * radious + padding,除非這是多於父視圖給出的空間。這就是說,如果你想繪製一個圓形,一個自定義視圖並不是真的要走,但我想你只是想學習如何構建自定義視圖。

相關問題