2016-03-01 60 views
0

我想獲得視圖和自定義視圖上的konwledges。我讀了一系列文章herethere。然後我決定看看Google如何編碼一些視圖。Android查看內部 - 自定義查看定位

我檢索了LabelView的代碼,並創建了一個應用程序,該應用程序由一個RelativLayout組成,該應用程序動態添加(修改的)LabelView。我試圖修改標籤的位置,覆蓋setX,setY。而不是有x,y爲左上方,我想有x,y視圖的中心。我所做的不工作(下面「3」和「30」這個數字應該有自己的中心在同一Ÿ對齊)

CustomLabel views are not centered

我加了一些日誌和地方提出的問題。

  • 爲什麼measureHeight和measureWidth調用幾次?
  • 爲什麼getWidht,getHeight,getRight和getBottom返回0?

在日誌下面(我刪除的內容是不相關):

... I/MainActivity: customLabel.width = 0 
... I/MainActivity: customLabel.height = 0 
... I/MainActivity: customLabel.getRight = 0 
... I/MainActivity: customLabel.getBottom = 0 
... I/MainActivity: customLabel2.width = 0 
... I/MainActivity: customLabel2.height = 0 
... I/MainActivity: customLabel2.getRight = 0 
... I/MainActivity: customLabel2.getBottom = 0 
... 
... I/CustomLabelView: (lbl2) measureWidth: result = 96 
... I/CustomLabelView: (lbl2) measureHeight: result = 99 
... I/CustomLabelView: (lbl1) measureWidth: result = 33 
... I/CustomLabelView: (lbl1) measureHeight: result = 61 
... I/CustomLabelView: (lbl2) measureWidth: result = 96 
... I/CustomLabelView: (lbl2) measureHeight: result = 99 
... I/CustomLabelView: (lbl1) measureWidth: result = 33 
... I/CustomLabelView: (lbl1) measureHeight: result = 61 
... 
... I/CustomLabelView: (lbl2) measureWidth: result = 96 
... I/CustomLabelView: (lbl2) measureHeight: result = 99 
... I/CustomLabelView: (lbl1) measureWidth: result = 33 
... I/CustomLabelView: (lbl1) measureHeight: result = 61 
... I/CustomLabelView: (lbl2) measureWidth: result = 96 
... I/CustomLabelView: (lbl2) measureHeight: result = 99 
... I/CustomLabelView: (lbl1) measureWidth: result = 33 
... I/CustomLabelView: (lbl1) measureHeight: result = 61 
... I/CustomLabelView: (lbl2) measureWidth: result = 96 
... I/CustomLabelView: (lbl2) measureHeight: result = 99 
... I/CustomLabelView: (lbl1) measureWidth: result = 33 
... I/CustomLabelView: (lbl1) measureHeight: result = 61 
... I/CustomLabelView: (lbl2) measureWidth: result = 96 
... I/CustomLabelView: (lbl2) measureHeight: result = 99 
... I/CustomLabelView: (lbl1) measureWidth: result = 33 
... I/CustomLabelView: (lbl1) measureHeight: result = 61 

下面MainActivity

public class MainActivity extends AppCompatActivity { 

    private final String TAG = getClass().getSimpleName(); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     RelativeLayout container = (RelativeLayout) findViewById(R.id.container); 

     CustomLabelView customLabel = new CustomLabelView(this, "lbl1"); 
     customLabel.setText("3"); 
     customLabel.setX(150); 
     customLabel.setY(200); 
     container.addView(customLabel); 

     Log.i(TAG, "customLabel.width = " + customLabel.getWidth()); 
     Log.i(TAG, "customLabel.height = " + customLabel.getHeight()); 
     Log.i(TAG, "customLabel.getRight = " + customLabel.getRight()); 
     Log.i(TAG, "customLabel.getBottom = " + customLabel.getBottom()); 

     CustomLabelView customLabel2 = new CustomLabelView(this, "lbl2"); 
     customLabel2.setText("66"); 
     customLabel2.setX(450); 
     customLabel2.setY(200); 
     customLabel2.setTextSize(80); 
     container.addView(customLabel2); 

     Log.i(TAG, "customLabel2.width = " + customLabel2.getWidth()); 
     Log.i(TAG, "customLabel2.height = " + customLabel2.getHeight()); 
     Log.i(TAG, "customLabel2.getRight = " + customLabel2.getRight()); 
     Log.i(TAG, "customLabel2.getBottom = " + customLabel2.getBottom()); 
    } 
} 

下面的LABELVIEW

/* 
* based on android-21/legacy/ApiDemos/src/com/example/android/apis/view/LabelView.java 
*/ 
public class CustomLabelView extends View { 

    private final String TAG = getClass().getSimpleName(); 

    private Paint mTextPaint; 
    private String mText; 
    private int mAscent; 

    //tag to identify instance in log 
    private String mTag; 

    /** 
    * Constructor. This version is only needed if you will be instantiating 
    * the object manually (not from a layout XML file). 
    * 
    * @param context 
    */ 
    public CustomLabelView(Context context, String tag) { 
     super(context); 
     initLabelView(); 
     mTag = tag; 
    } 


    private final void initLabelView() { 
     mTextPaint = new Paint(); 
     mTextPaint.setAntiAlias(true); 
     // Must manually scale the desired text size to match screen density 
     mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density); 
     mTextPaint.setColor(0xFF000000); 
     setPadding(3, 3, 3, 3); 
    } 

    /** 
    * Sets the text to display in this label 
    * 
    * @param text The text to display. This will be drawn as one line. 
    */ 
    public void setText(String text) { 
     mText = text; 
     requestLayout(); 
     invalidate(); 
    } 

    /** 
    * Sets the text size for this label 
    * 
    * @param size Font size 
    */ 
    public void setTextSize(int size) { 
     // This text size has been pre-scaled by the getDimensionPixelOffset method 
     mTextPaint.setTextSize(size); 
     requestLayout(); 
     invalidate(); 
    } 

    /** 
    * Sets the text color for this label. 
    * 
    * @param color ARGB value for the text 
    */ 
    public void setTextColor(int color) { 
     mTextPaint.setColor(color); 
     invalidate(); 
    } 

    /** 
    * @see android.view.View#measure(int, int) 
    */ 
    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     setMeasuredDimension(measureWidth(widthMeasureSpec), 
       measureHeight(heightMeasureSpec)); 
    } 

    /** 
    * Determines the width of this view 
    * 
    * @param measureSpec A measureSpec packed into an int 
    * @return The width of the view, honoring constraints from measureSpec 
    */ 
    private int measureWidth(int measureSpec) { 
     int result = 0; 
     int specMode = MeasureSpec.getMode(measureSpec); 
     int specSize = MeasureSpec.getSize(measureSpec); 

     if (specMode == MeasureSpec.EXACTLY) { 
      // We were told how big to be 
      result = specSize; 
     } else { 
      // Measure the text 
      result = (int) mTextPaint.measureText(mText) + getPaddingLeft() 
        + getPaddingRight(); 
      if (specMode == MeasureSpec.AT_MOST) { 
       // Respect AT_MOST value if that was what is called for by measureSpec 
       result = Math.min(result, specSize); 
      } 
     } 

     Log.i(TAG, "(" + mTag + ") measureWidth: result = " + result); 

     return result; 
    } 

    /** 
    * Determines the height of this view 
    * 
    * @param measureSpec A measureSpec packed into an int 
    * @return The height of the view, honoring constraints from measureSpec 
    */ 
    private int measureHeight(int measureSpec) { 
     int result = 0; 
     int specMode = MeasureSpec.getMode(measureSpec); 
     int specSize = MeasureSpec.getSize(measureSpec); 

     mAscent = (int) mTextPaint.ascent(); 
     if (specMode == MeasureSpec.EXACTLY) { 
      // We were told how big to be 
      result = specSize; 
     } else { 
      // Measure the text (beware: ascent is a negative number) 
      result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop() 
        + getPaddingBottom(); 
      if (specMode == MeasureSpec.AT_MOST) { 
       // Respect AT_MOST value if that was what is called for by measureSpec 
       result = Math.min(result, specSize); 
      } 
     } 

     Log.i(TAG, "(" + mTag + ") measureHeight: result = " + result); 

     return result; 
    } 

    /** 
    * Render the text 
    * 
    * @see android.view.View#onDraw(android.graphics.Canvas) 
    */ 
    @Override 
    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
     canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint); 
    } 


    @Override 
    public void setX(float x) { 
     float x_center = x + getWidth()/2; 
     super.setX(x_center); 

     super.setX(x_center); 
    } 

    @Override 
    public void setY(float y) { 
     float y_center = y - getHeight()/2; 
     super.setY(y_center); 
    } 
} 

回答

1

爲什麼measureHeightmeasureWidth叫幾次?

measureHeightmeasureWidth電話是onMeasure回調的結果。

這一個被稱爲「,以確定該視圖及其所有子女」(閱讀更多here)的大小要求。這基本上意味着當View或這個View被放置時,需要知道這個View具有什麼尺寸要求,它導致onMeasure被調用。

重要的是它導致onMeasure被調用。它不直接調用它。你不應該自己撥打onMeasure。最簡單的解釋方法是this View lifecycle diagram。在View上致電requestLayout將導致其調用onMeasure。請注意,您的CustomLabelView在某些方法中也稱爲requestLayout

有沒有真正的方式來確定onMeasure電話的確切數量,因爲它可以取決於Layout您使用的層次結構中的類型,你View行爲和其他Views'變化。


爲什麼getWidthgetHeightgetRightgetBottom返回0?

您正試圖在您的ActivityonCreate中打電話給他們。這意味着你的Activity剛創建完畢,屏幕上已經沒有任何東西了。換句話說,「佈局通行證」尚未執行。這基本上意味着你的CustomLabelView還沒有被繪製。如果它沒有繪製它沒有尺寸(這就是爲什麼所有參數都是0)。

如果你試圖把下面的代碼在你的onCreate,你可能會得到非0值(2秒後):

final Handler handler = new Handler(); 
handler.postDelayed(new Runnable() { 
    @Override 
    public void run() { 
     Log.i(TAG, "customLabel.width = " + customLabel.getWidth()); 
     Log.i(TAG, "customLabel.height = " + customLabel.getHeight()); 
     Log.i(TAG, "customLabel.getRight = " + customLabel.getRight()); 
     Log.i(TAG, "customLabel.getBottom = " + customLabel.getBottom()); 
    } 

}, 2000); 

要記得標記您customLabelfinal

+0

Thanks @Bartek!你對第一個問題的回答是在12點50分(https://www.youtube.com/watch?v=NYtB6mlu7vA)確認的,據說「Viewgroups會在eacf的子視圖中調用Measure」 –