How to lay out Views in RelativeLayout programmatically?

前端 未结 9 1676
心在旅途
心在旅途 2020-11-22 15:04

I\'m trying to achieve the following programmatically (rather than declaratively via XML):


   

        
相关标签:
9条回答
  • 2020-11-22 15:33

    This approach with ViewGroup.MarginLayoutParams worked for me:

    RelativeLayout myLayout = (RelativeLayout) findViewById(R.id.my_layout);
    
    TextView someTextView = ...
    
    int leftMargin = Util.getXPos();
    int topMargin = Util.getYPos();
    
    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
        new ViewGroup.MarginLayoutParams(
            RelativeLayout.LayoutParams.WRAP_CONTENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT));
    
    lp.setMargins(leftMargin, topMargin, 0, 0);
    
    myLayout.addView(someTextView, lp);
    
    0 讨论(0)
  • 2020-11-22 15:33
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //setContentView(R.layout.activity_main);
    
            final RelativeLayout relativeLayout = new RelativeLayout(this);
            final TextView tv1 = new TextView(this);
            tv1.setText("tv1 is here");
            // Setting an ID is mandatory.
            tv1.setId(View.generateViewId());
            relativeLayout.addView(tv1);
    
    
            final TextView tv2 = new TextView(this);
            tv2.setText("tv2 is here");
    
            // We are defining layout params for tv2 which will be added to its  parent relativelayout.
            // The type of the LayoutParams depends on the parent type.
            RelativeLayout.LayoutParams tv2LayoutParams = new  RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT);
    
            //Also, we want tv2 to appear below tv1, so we are adding rule to tv2LayoutParams.
            tv2LayoutParams.addRule(RelativeLayout.BELOW, tv1.getId());
    
            //Now, adding the child view tv2 to relativelayout, and setting tv2LayoutParams to be set on view tv2.
            relativeLayout.addView(tv2);
            tv2.setLayoutParams(tv2LayoutParams);
            //Or we can combined the above two steps in one line of code
            //relativeLayout.addView(tv2, tv2LayoutParams);
    
            this.setContentView(relativeLayout);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-22 15:35

    If you really want to layout manually, i'd suggest not to use a standard layout at all. Do it all on your own, here a kotlin example:

    class ProgrammaticalLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ViewGroup(context, attrs, defStyleAttr) { 
        private val firstTextView = TextView(context).apply {
            test = "First Text"
        }
    
        private val secondTextView = TextView(context).apply {
            text = "Second Text"
        }
    
        init {
            addView(firstTextView)
            addView(secondTextView)
        }
    
        override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
            // center the views verticaly and horizontaly
            val firstTextLeft = (measuredWidth - firstTextView.measuredWidth) / 2
            val firstTextTop = (measuredHeight - (firstTextView.measuredHeight + secondTextView.measuredHeight)) / 2
            firstTextView.layout(firstTextLeft,firstTextTop, firstTextLeft + firstTextView.measuredWidth,firstTextTop + firstTextView.measuredHeight)
    
            val secondTextLeft = (measuredWidth - secondTextView.measuredWidth) / 2
            val secondTextTop = firstTextView.bottom
            secondTextView.layout(secondTextLeft,secondTextTop, secondTextLeft + secondTextView.measuredWidth,secondTextTop + secondTextView.measuredHeight)
        }
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 
            // just assume we`re getting measured exactly by the parent
            val measuredWidth = MeasureSpec.getSize(widthMeasureSpec)
            val measuredHeight = MeasureSpec.getSize(heightMeasureSpec)
    
            firstTextView.measures(MeasureSpec.makeMeasureSpec(meeasuredWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
            secondTextView.measures(MeasureSpec.makeMeasureSpec(meeasuredWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
    
            setMeasuredDimension(measuredWidth, measuredHeight)
        }
    }
    

    This might give you an idea how this could work

    0 讨论(0)
  • 2020-11-22 15:40

    Cut the long story short: With relative layout you position elements inside the layout.

    1. create a new RelativeLayout.LayoutParams

      RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(...)
      

      (whatever... fill parent or wrap content, absolute numbers if you must, or reference to an XML resource)

    2. Add rules: Rules refer to the parent or to other "brothers" in the hierarchy.

      lp.addRule(RelativeLayout.BELOW, someOtherView.getId())
      lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT)
      
    3. Just apply the layout params: The most 'healthy' way to do that is:

      parentLayout.addView(myView, lp)
      

    Watch out: Don't change layout from the layout callbacks. It is tempting to do so because this is when views get their actual sizes. However, in that case, unexpected results are expected.

    0 讨论(0)
  • 2020-11-22 15:40

    Android 22 minimal runnable example

    Source:

    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    public class Main extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            final RelativeLayout relativeLayout = new RelativeLayout(this);
    
            final TextView tv1;
            tv1 = new TextView(this);
            tv1.setText("tv1");
            // Setting an ID is mandatory.
            tv1.setId(View.generateViewId());
            relativeLayout.addView(tv1);
    
            // tv2.
            final TextView tv2;
            tv2 = new TextView(this);
            tv2.setText("tv2");
            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.FILL_PARENT);
            lp.addRule(RelativeLayout.BELOW, tv1.getId());
            relativeLayout.addView(tv2, lp);
    
            // tv3.
            final TextView tv3;
            tv3 = new TextView(this);
            tv3.setText("tv3");
            RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
            );
            lp2.addRule(RelativeLayout.BELOW, tv2.getId());
            relativeLayout.addView(tv3, lp2);
    
            this.setContentView(relativeLayout);
        }
    }
    

    Works with the default project generated by android create project .... GitHub repository with minimal build code.

    0 讨论(0)
  • 2020-11-22 15:41

    call

    tv1.setId(1) 
    

    after

    tv1.setText("A");
    
    0 讨论(0)
提交回复
热议问题