Android ViewGroup:我应该在onLayout()覆盖中做什么?

时间:2013-07-07 20:00:25

标签: android android-layout android-view

扩展Android ViewGroup类时,onLayout()覆盖的目的是什么?我在Android中进行自定义控件但由于某种原因,内容(子View个对象)未显示。我的方法是扩展ViewGroup类,通过ViewGroup的addView()方法添加子视图。然后,在我的主要活动中,我有以下代码:

ChannelController myCC = new ChannelController(this); 
setContentView(myCC); 

ChannelController是我的自定义类的名称,它扩展了ViewGroup。我必须做错事,因为屏幕上没有显示任何内容。

我明白我必须覆盖并实现onLayout()方法,但是用什么?我知道在dev.android网站上有一整页专门用于此,但它对我没有多大帮助,主要是因为我认为我是新手。任何见解都将不胜感激。

作为参考,我的ViewGroup扩展如下所示:

public class ChannelController extends ViewGroup {

    final String TAG = "JAL"; 

    public ChannelController(Context c) 
    {   
        super(c); 
        init(c); 
    }

    public ChannelController(Context c, AttributeSet attibset)
    {
        super(c); 
        init(c); 
    }

    public ChannelController(Context c, AttributeSet attribset, int defStyle)
    {
        super(c); 
        init(c); 
    }

    public void init(Context c)
    {
        //RelativeLayout wrap = new RelativeLayout(c);
        RelativeLayout.LayoutParams wrapLP = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.MATCH_PARENT, 
                RelativeLayout.LayoutParams.WRAP_CONTENT); 

        RelativeLayout r1 = new RelativeLayout(c); 
        RelativeLayout.LayoutParams r1LP = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.MATCH_PARENT, 
                RelativeLayout.LayoutParams.WRAP_CONTENT); 

        RelativeLayout r2 = new RelativeLayout(c); 
        RelativeLayout.LayoutParams r2LP = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.MATCH_PARENT, 
                RelativeLayout.LayoutParams.WRAP_CONTENT); 

        TextView t = new TextView(c); 
        RelativeLayout.LayoutParams tlp = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
        Button m = new Button(c); 
        RelativeLayout.LayoutParams mlp = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
        Button s = new Button(c); 
        RelativeLayout.LayoutParams slp = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
        SeekBar f = new SeekBar(c); 
        RelativeLayout.LayoutParams flp = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 

        t.setId(1); 
        m.setId(2); 
        s.setId(3); 
        f.setId(4); 
        r1.setId(5); 
        r2.setId(6); 

        t.setText("CHANNELNAME"); 
        t.setTextColor(Color.BLACK);
        tlp.setMargins(30, 0, 0, 0); 
        tlp.addRule(RelativeLayout.LEFT_OF, m.getId()); 
        tlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT); 
        tlp.addRule(RelativeLayout.CENTER_VERTICAL); 
        tlp.addRule(RelativeLayout.CENTER_HORIZONTAL); 

        m.setText("M"); 
        m.setBackgroundColor(Color.rgb(237, 155, 31));
        m.setTextColor(Color.WHITE); 
        mlp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 
        mlp.addRule(RelativeLayout.ALIGN_PARENT_TOP); 
        m.setTextSize(10); 

        flp.addRule(RelativeLayout.LEFT_OF, s.getId()); 
        flp.addRule(RelativeLayout.ALIGN_PARENT_LEFT); 
        flp.addRule(RelativeLayout.CENTER_VERTICAL); 

        s.setText("S"); 
        s.setTextSize(10); 
        s.setBackgroundColor(Color.rgb(192, 48, 46)); 
        s.setTextColor(Color.WHITE); 
        slp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 
        slp.addRule(RelativeLayout.ALIGN_PARENT_TOP); 

        r1.addView(t, tlp); 
        r1.addView(m, mlp); 
        r2.addView(f, flp);
        r2.addView(s, slp); 

        r1.setBackgroundColor(Color.rgb(233, 242, 251)); 
        r2.setBackgroundColor(Color.rgb(233, 242, 251)); 

        r1LP.addRule(RelativeLayout.ALIGN_PARENT_TOP); 
        r2LP.addRule(RelativeLayout.BELOW, r1.getId()); 

        this.addView(r1, r1LP); 
        this.addView(r2, r2LP); 

        this.setLayoutParams(wrapLP); 

        //this.addView(wrap); 

        Log.i(TAG, "ChannelController constructor was called"); 
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // TODO Auto-generated method stub
        //super.onLayout(changed, l, t, r, b); 

    }

}

在onLayout方法覆盖中我需要做什么?

2 个答案:

答案 0 :(得分:44)

onLayout中,您需要为此layout的每个孩子调用ViewGroup方法,并为他们提供所需的位置(相对于父级)。您可以查看FrameLayoutViewGroup的最简单子类之一)的源代码,了解其工作原理。

虽然,如果您不需要任何“特殊”布局,您还有其他选择:

  • 扩展ViewGroup的另一个子类(例如FrameLayout
  • 使用LayoutInflater如果你只需要你的控件看起来与XML完全一样(我认为,这正是你的情况)

答案 1 :(得分:0)

实际上,它有助于定位视图组的子级。以下代码可能有帮助

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
MarginLayoutParams layoutParams = (MarginLayoutParams) icon.getLayoutParams();

// Figure out the x-coordinate and y-coordinate of the icon.
int x = getPaddingLeft() + layoutParams.leftMargin;
int y = getPaddingTop() + layoutParams.topMargin;

// Layout the icon.
icon.layout(x, y, x + icon.getMeasuredWidth(), y + icon.getMeasuredHeight());

// Calculate the x-coordinate of the title: icon's right coordinate +
// the icon's right margin.
x += icon.getMeasuredWidth() + layoutParams.rightMargin;

// Add in the title's left margin.
layoutParams = (MarginLayoutParams) titleView.getLayoutParams();
x += layoutParams.leftMargin;

// Calculate the y-coordinate of the title: this ViewGroup's top padding +
// the title's top margin
y = getPaddingTop() + layoutParams.topMargin;

// Layout the title.
titleView.layout(x, y, x + titleView.getMeasuredWidth(), y + titleView.getMeasuredHeight());

// The subtitle has the same x-coordinate as the title. So no more calculating there.

// Calculate the y-coordinate of the subtitle: the title's bottom coordinate +
// the title's bottom margin.

...

您可以在此处找到有关自定义视图的更多详细信息 custom views