TextView tv1 = new TextView(this);
tv1.setPadding(5, 0, 5, 0);
tv1.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
tv1.setBackgroundColor(Color.parseColor("#0099cc"));
tv1.setTextColor(Color.WHITE);
tv1.setTextSize(11);
tv1.setGravity(Gravity.LEFT | Gravity.BOTTOM);
tv1.setText("Test1");
ll.addView(tv1);
TextView tv2 = new TextView(this);
tv2.setPadding(5, 0, 5, 0);
tv2.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
tv2.setBackgroundColor(Color.parseColor("#0099cc"));
tv2.setTextColor(Color.WHITE);
tv2.setTextSize(11);
tv2.setGravity(Gravity.LEFT | Gravity.BOTTOM);
tv2.setText("Test2");
ll.addView(tv2);
As you can see, in this peace of code I set TextView's background color. What I want to do is I want to separate both of these TextView's from each other, so that their background colors would be separated by a line. I don't want them to connect. As I understand, it would be possible to do so, if I could set margins of TextView, but as I know, TextView's are not able to do so.
set to LayoutParams.
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(10,10,10,10);
tv1.setLayoutParams(params);
It depends according to your parent view.
If you using LinearLayout on your textview as a parent view give params like below
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(10,10,10,10);
tv1.setLayoutParams(params);
If you using RelativeLayout on your textview as a parent view give params like below
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(10,10,10,10);
tv1.setLayoutParams(params);
For Kotlin use following code snippet
(textView.layoutParams as ConstraintLayout.LayoutParams).apply {
marginStart=8.dpToPixels()
topMargin=8.dpToPixels()
marginEnd=8.dpToPixels()
bottomMargin=8.dpToPixels()
}
Change LayoutParams as per used layout.
Thanks.
All these answers are great, but I was using ConstraintLayout, so here is code for that:
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(10, 10, 10, 10);
textview.setLayoutParams(params); // note that textview would be your instanced TextView object
In Kotlin I do like this:
binding.playBtn.updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(0,16,0,0) //parameters are in pixel
}
binding.playBtn.setPadding(10)
This one should be tried
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT);
params.setMargins(10,20,30,20);
txt_gender.setLayoutParams(params);
set margins for TextView programmatically
Here The way That you can use it any where in your Application
create a Object class and add this code there
fun setMargin(left: Int, top: Int, right: Int, bottom: Int, textView: TextView){
val params: LinearLayout.LayoutParams =
LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
params.setMargins(left, top, right, bottom)
textView.setLayoutParams(params)
}
Then you can call it anywhere and use it for any TextView of course you can change the layout for anything you want.
you can call this function like this.
setMargin(0, 70, 0, 0, title)
Using Kotlin Extensions:
Here is simple extension for setting margins for textview.
fun View.setMargins(marginLeft: Int, marginTop: Int, marginRight: Int, marginBottom: Int) {
val params: LinearLayout.LayoutParams =
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
params.setMargins(margin.dp, 0, margin.dp, 0)
this.layoutParams = params
}
For Int to dp conversion, here is another extension
val Int.dp: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
You can call this extension to give horizontal margin 8dp as follows
yourTextView.setMargins(8, 0, 8, 0)
If you use Kotlin ex. in Adapter add like this:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val params = holder.tvNext.layoutParams as MarginLayoutParams
params.bottomMargin=0
You can give the margin to any textview with this simple code
TextView textView = new TextView(this);
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) textView.getLayoutParams();
params.setMargins(20, 30, 40, 50);
textView.setLayoutParams(params);
Related
I am adding some View to the LinearLayout dynamically:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(100, 100, 100, 100);
view.setLayoutParams(params);
parent.addView(view);
However, the margins are not getting applied. The following:
view.invalidate();
view.requestLayout();
parent.invalidate();
parent.requestLayout();
didn't work. However, if I force the activity to recreate (e.g. turn off and on my mobile phone), the margins get applied. Calling activity.recreate() also works, but it's too slow.
How to force layout to recalculate margins? Probably, there's something wrong in the flow? I tried to add my views to the root after creation, add children before and after applying properties, but this didn't work for me.
UPD:
I tried to repeat the bug programmatically and got it with this code:
LinearLayout base = new LinearLayout(context);
LayoutParams params1 = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
base.setLayoutParams(params1);
base.setBackgroundColor(Color.CYAN);
root.addView(base);
LinearLayout another1 = new LinearLayout(context);
LayoutParams params2 = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
another1.setLayoutParams(params2);
another1.setOrientation(LinearLayout.VERTICAL);
another1.setBackgroundColor(Color.BLUE);
base.addView(another1);
TextView tv1 = new TextView(context);
tv1.setText("SOME TEST TEXT 1");
tv1.setTextColor(Color.BLACK);
LayoutParams params4 = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params4.setMargins(100, 100, 100, 100);
tv1.setLayoutParams(params4);
another1.addView(tv1);
TextView tv2 = new TextView(context);
tv2.setText("SOME TEST TEXT 2");
tv2.setTextColor(Color.BLACK);
LayoutParams params5 = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params4.setMargins(100, 100, 100, 100);
tv2.setLayoutParams(params5);
another1.addView(tv2);
I expect margins to be applied, but they are not. What is the correct order of initializing such a view?
So, my trouble was in DP to PX converter that just wasn't initialized at that moment. However, to clarify everything, my example above is just an error (I didn't change params4 to params5 when adding the second TextView.
Also while testing everything, I found out that the order of adding layouts and their parameters doesn't matter at all.
You probably added child views to the parent view in onCreate().
In onCreate(), parent view does not have actual size.
If you have to do it in onCreate(), try following code.
final ViewTreeObserver observer = parent.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
LinearLayout.LayoutParams params = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(100, 100, 100, 100);
TextView view = new TextView(context);
view.setLayoutParams(params);
parent.addView(view);
observer.removeOnGlobalLayoutListener(this);
}
};
Hope this will help!
Try this:
LinearLayout ll = findViewById(R.id.linearLayout);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(30,20,30,0);
Hope this will help!
I need dynamic create the texview, it works just the text content show VERTICAL but HORIZONTAL
TextView tv = new TextView(this.theContext);
tv.setText(this.getTip(0));
tv.setBackgroundColor(Color.BLUE);
tv.setGravity(Gravity.CENTER_HORIZONTAL);
tv.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 0);
params.gravity = Gravity.CENTER;
this.addView(tv, params);
mLeftLabel = tv;
also, I set the layout :
tv.layout(l,t,r,b); . but I think that this statement should not effect the text Direction, is it right ?
please give help or tip, thanks.
try to follow the example below:
TextView tv = new TextView(this);
tv.setText("text");
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 0);
params.gravity = Gravity.CENTER;
mainLayout.addView(tv, params);
try changing LayoutParams as
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
setting gravity to center when you are using WRAP_CONTENT for textview does not seem to make sense, though I am not sure.
If I use xml file I have a option called layout_margin (for example layout_margin ="1dp" for text view ) but I want to set programmatically and I dont know how to do it.
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)textview.getLayoutParams();
params.setMargins(20, 0, 0, 0);
textview.setLayoutParams(params);
Please Google before adding your question to StackOverflow.
TextView tv = (TextView)findViewById(R.id.my_text_view);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)tv.getLayoutParams();
params.setMargins(0, 0, 10, 0); //substitute parameters for left, top, right, bottom
tv.setLayoutParams(params);
Note, that not all LayoutParams has method setMargins();
RelativeLayout, LinearLayout etc has their own inner class LayoutParams, so availability of setMargins is not always available.
You can do by this:
TextView text = (TextView) findViewById(R.id.text);
LinearLayout.LayoutParams params= new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(left, top, right, bottom);//pass int values for left,top,right,bottom
text.setLayoutParams(params);
TextView tv = (TextView) findViewById(R.id.tvId);
LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
llp.setMargins(50, 0, 0, 0); // llp.setMargins(left, top, right, bottom);
tv.setLayoutParams(llp);
Try This: It worked...
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(0, 10, 0, 0);
firstName.setLayoutParams(params);
You can use the setMargins() on the LinearLayout.LayoutParams. See the answer of this StackOverflow question for more information.
TextView tv = (TextView)findViewById(R.id.item_title));
RelativeLayout.LayoutParams mRelativelp = (RelativeLayout.LayoutParams) tv
.getLayoutParams();
mRelativelp.setMargins(DptoPxConvertion(15), 0, DptoPxConvertion (15), 0);
tv.setLayoutParams(mRelativelp);
private int DptoPxConvertion(int dpValue)
{
return (int)((dpValue * mContext.getResources().getDisplayMetrics().density) + 0.5);
}
getLayoutParams() of textview should be casted to the corresponding Params based on the Parent of the textview in xml.
<RelativeLayout>
<TextView
android:id="#+id/item_title">
</RelativeLayout>
If parent of the TextView is RelativeLayout means, then RelativeLayout.LayoutParams as above. If parent is LinearLayout means then
LinearLayout.LayoutParams mLinearlp = (LinearLayout.LayoutParams) tv
.getLayoutParams();
To render the same real size on different devices use DptoPxConvertion() method which I have used above. setMargin(left,top,right,bottom) params will take values in pixel not in dp.
I'm trying to achieve the following programmatically (rather than declaratively via XML):
<RelativeLayout...>
<TextView ...
android:id="#+id/label1" />
<TextView ...
android:id="#+id/label2"
android:layout_below: "#id/label1" />
</RelativeLayout>
In other words, how do I make the second TextView appear below the first one, but I want to do it in code:
RelativeLayout layout = new RelativeLayout(this);
TextView label1 = new TextView(this);
TextView label2 = new TextView(this);
...
layout.addView(label1);
layout.addView(label2);
setContentView(layout);
Update:
Thanks, TreeUK. I understand the general direction, but it still doesn't work - "B" overlaps "A". What am I doing wrong?
RelativeLayout layout = new RelativeLayout(this);
TextView tv1 = new TextView(this);
tv1.setText("A");
TextView tv2 = new TextView(this);
tv2.setText("B");
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.FILL_PARENT);
lp.addRule(RelativeLayout.RIGHT_OF, tv1.getId());
layout.addView(tv1);
layout.addView(tv2, lp);
From what I've been able to piece together, you have to add the view using LayoutParams.
LinearLayout linearLayout = new LinearLayout(this);
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
parentView.addView(linearLayout, relativeParams);
All credit to sechastain, to relatively position your items programmatically you have to assign ids to them.
TextView tv1 = new TextView(this);
tv1.setId(1);
TextView tv2 = new TextView(this);
tv2.setId(2);
Then addRule(RelativeLayout.RIGHT_OF, tv1.getId());
Cut the long story short:
With relative layout you position elements inside the layout.
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)
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)
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.
Just spent 4 hours with this problem. Finally realized that you must not use zero as view id. You would think that it is allowed as NO_ID == -1, but things tend to go haywire if you give it to your view...
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.
call
tv1.setId(1)
after
tv1.setText("A");
Try:
EditText edt = (EditText) findViewById(R.id.YourEditText);
RelativeLayout.LayoutParams lp =
new RelativeLayout.LayoutParams
(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
);
lp.setMargins(25, 0, 0, 0); // move 25 px to right (increase left margin)
edt.setLayoutParams(lp); // lp.setMargins(left, top, right, bottom);
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);
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);
}
}
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
I'm trying to achieve the following programmatically (rather than declaratively via XML):
<RelativeLayout...>
<TextView ...
android:id="#+id/label1" />
<TextView ...
android:id="#+id/label2"
android:layout_below: "#id/label1" />
</RelativeLayout>
In other words, how do I make the second TextView appear below the first one, but I want to do it in code:
RelativeLayout layout = new RelativeLayout(this);
TextView label1 = new TextView(this);
TextView label2 = new TextView(this);
...
layout.addView(label1);
layout.addView(label2);
setContentView(layout);
Update:
Thanks, TreeUK. I understand the general direction, but it still doesn't work - "B" overlaps "A". What am I doing wrong?
RelativeLayout layout = new RelativeLayout(this);
TextView tv1 = new TextView(this);
tv1.setText("A");
TextView tv2 = new TextView(this);
tv2.setText("B");
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.FILL_PARENT);
lp.addRule(RelativeLayout.RIGHT_OF, tv1.getId());
layout.addView(tv1);
layout.addView(tv2, lp);
From what I've been able to piece together, you have to add the view using LayoutParams.
LinearLayout linearLayout = new LinearLayout(this);
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
parentView.addView(linearLayout, relativeParams);
All credit to sechastain, to relatively position your items programmatically you have to assign ids to them.
TextView tv1 = new TextView(this);
tv1.setId(1);
TextView tv2 = new TextView(this);
tv2.setId(2);
Then addRule(RelativeLayout.RIGHT_OF, tv1.getId());
Cut the long story short:
With relative layout you position elements inside the layout.
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)
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)
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.
Just spent 4 hours with this problem. Finally realized that you must not use zero as view id. You would think that it is allowed as NO_ID == -1, but things tend to go haywire if you give it to your view...
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.
call
tv1.setId(1)
after
tv1.setText("A");
Try:
EditText edt = (EditText) findViewById(R.id.YourEditText);
RelativeLayout.LayoutParams lp =
new RelativeLayout.LayoutParams
(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
);
lp.setMargins(25, 0, 0, 0); // move 25 px to right (increase left margin)
edt.setLayoutParams(lp); // lp.setMargins(left, top, right, bottom);
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);
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);
}
}
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