I'd like to place a view on top of an existing view. The view I'm targeting is inside a LinearLayout, which resides in a FrameLayout.
I'm thinking there's a way to do this with RelativeLayout because I already have it partially working. I'd like to align the new view to the bottom-left or top-left (as the origin) and then offset X and Y to some precise value that I specify.
How can this be achieved?
Here's the idea:
public static void placeTextRelativeToBottomLeftOfViewAtXY(final FrameLayout layout, View component, int x, int y, String text) {
final TextView textView = new TextView(getContext());
textView.setId((int)System.currentTimeMillis());
final RelativeLayout relativeLayout = new RelativeLayout(getContext());
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
params.setMargins(x, y, 0,0);
params.addRule(RelativeLayout.LEFT_OF, component.getId());
relativeLayout.setLayoutParams(params);
relativeLayout.setBackgroundColor(Color.TRANSPARENT);
textView.setText("+500 points!");
textView.bringToFront();
relativeLayout.addView(textView, params);
layout.addView(relativeLayout);
}
Based on the additional information in comments, even if it is possible to overlap a different layouts inside a FrameLayout, those layouts will only be able to position their own children.
A RelativeLayout won't be able to position one of its child views relative to a view in a different sibling or parent Layout.
The way to go would be to flattern the heierarchy of Layouts, setting the root layout to a RelativeLayout or a ConstraintLayout.
ConstraintLayout is more flexible in terms of positioning views, but it is also more difficult to learn.
Here I am leaving an alternative to be used with RelativeLayout as the root view. The important items to look at are the setting of the LayoutParams which is sometimes a bit confussing.
The LayoutParams are set on the child view, but the class used depends on the parent view.
Also take in mind that to keep margins display independent you need to convert dp into pixels (for the sake of simplicity I haven't done that, but there are examples of how to do this here in SO).
It also uses View.generteViewId() go get an id for a view created dynamically.
To make it simple I included the reference View in the xml, but i could have also been created dynamically.
Layout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rlContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tvCenterText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Texto estatico"
android:layout_centerInParent="true"/>
</RelativeLayout>
Main Activity
public class DynamicViewsActivity extends AppCompatActivity {
RelativeLayout rlContainer;
TextView centerText;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamicviews);
rlContainer = findViewById(R.id.rlContainer);
centerText = findViewById(R.id.tvCenterText);
placeTextRelativeToBottomLeftOfViewAtXY(rlContainer, centerText, 100,10, "Hola");
}
public void placeTextRelativeToBottomLeftOfViewAtXY(final RelativeLayout layout, View component, int x, int y, String text) {
final TextView textView = new TextView(this);
textView.setId(View.generateViewId());
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(x, y, x,y);
params.addRule(RelativeLayout.LEFT_OF, component.getId());
params.addRule(RelativeLayout.ALIGN_BASELINE, component.getId());
textView.setLayoutParams(params);
textView.setText(text);
layout.addView(textView);
}
}
I want to create vertical LinearLayout with couple of Button children, where each child has width of widest of them.
However depending on using MATCH_PARENT or WRAP_CONTENT for children width, I get either LinearLayout taking whole screen's width, or Buttons not filling LinearLayout. Screenshots below (fill/wrap):
Example Activity code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RelativeLayout mainView = new RelativeLayout(this);
mainView.setBackgroundColor(Colors.WHITE);
String[] buttonsNames = new String[] { "Short", "Looooooong", "Medium" };
View buttonsView = getButtonsView(buttonsNames);
mainView.addView(buttonsView, new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
setContentView(mainView);
}
private View getButtonsView(String[] buttonNames) {
LinearLayout buttonsView = new LinearLayout(this);
buttonsView.setOrientation(LinearLayout.VERTICAL);
buttonsView.setBackgroundColor(Colors.BLACK);
for (int i = 0; i < buttonNames.length; i++) {
Button button = new Button(this);
button.setText(buttonNames[i]);
///////////// HERE LAYS THE PROBLEM //////////
buttonsView.addView(button, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
//LinearLayout.LayoutParams.WRAP_CONTENT, // neither of them works
LinearLayout.LayoutParams.WRAP_CONTENT));
View redLineDivider = new View(this);
redLineDivider.setBackgroundColor(Colors.RED);
buttonsView.addView(redLineDivider, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, 2));
}
return buttonsView;
}
As you can see on second screenshot, red lines actually take whole width without stretching LinearLayout - it is because at least one view has set width.
Potential fix I have came up with is to find widest button (with longest text) and make it use WRAP_CONTENT, while all the rest use MATCH_PARENT, which gives me expected result:
Code:
buttonsView.addView(button, new LinearLayout.LayoutParams(
isLongestText(i) ? LinearLayout.LayoutParams.WRAP_CONTENT
: LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
It doesn't feel like elegant solution though - is there any intended mechanism for situation like this, that I am missing out?
Following is the trick:
Mention the width of the LinearLayout containing the buttons (buttonsView in your code) as WRAP_CONTENT.
Mention the width of each button as MATCH_PARENT
Your program should give you the expected result if you do not include the redLineDivider View. There seems to be some issue with setting the width of redLineDivider. As an alternative you can declare it as a LinearLayout to make your code work perfectly.
// View redLineDivider = new View(this);
// Instead declare it as a LinearLayout
LinearLayout redLineDivider = new LinearLayout(this);
Hope this will be useful.
I am currently having a programatically created framelayout with a imageview and a text view. By original layout is relative layout.
RelativeLayout layout = (RelativeLayout) findViewById(R.id.rel);
FrameLayout fr = new FrameLayout(this);
fr.setBackgroundResource(R.drawable.question_bar_icon);
ImageView b1 = new ImageView(this);
TextView b2 = new TextView(this);
b1.setBackgroundResource(R.drawable.mcq);
fr.addView(b1);
fr.addView(b2);
layout.addView(fr);
Now i am unable to resize the imageview and the button, also m unable to position them, in the sence textview in the center and imageview in the verticle center and left positioned.
I tried layout params, but not working, any help would be greatly appreciated!
Try using the overloaded version of addView that takes a LayoutParameter as well in every case you are programatically adding a view, otherwise it is inserted to the ViewGroup with default layout parameters. (P.S. you can also control the order of insertion).
For example for the ImageView you wanted to be in the center of the frame layout:
int width = FrameLayout.LayoutParams.WRAP_CONTENT; //or whatever you want
int height= FrameLayout.LayoutParams.WRAP_CONTENT; //or whatever you want
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(width, height, Gravity.CENTER);
fr.addView(b1,lp);
Do the same for the other view, and most importantly, do the same, using RelativeLayout.LayoutParams for inserting the frame element itself into your RelativeLayout.
I'm having trouble adding an imageview to a relative layout. I would like to add an image to a list of menu items that I am creating dynamically using RelativeLayout. All of my menu items show up just fine and in order but when I try to add an image to each of the items I only get one arrow and it is not centered vertically. Below is my code.
In my XML file
<RelativeLayout
android:id="#+id/pMenu"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
In my code:
private void buildMenu(String name, int id) {
String[] menuItems = getResources().getStringArray(pMenus[id]);
// Get the rel layout from xml
RelativeLayout container = (RelativeLayout) findViewById(R.id.pMenu);
int imageId=1;
Typeface tf = Typeface.createFromAsset(this.getAssets(),"mreavesmodot-reg.otf");
for(String menuItem: menuItems) {
// Defining the layout parameters
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
StyledButton menuImage = new StyledButton(this);
menuImage.setBackgroundResource(R.drawable.menu_button);
menuImage.setText(menuItem);
menuImage.setTypeface(tf);
menuImage.setTextSize(19);
menuImage.setPadding(20, 0, 0, 0);
menuImage.setTextColor(Color.WHITE);
menuImage.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
menuImage.setOnClickListener(getOnClickListener(menuImage, name));
menuImage.setId(imageId);
if(imageId==1) {
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
} else {
lp.addRule(RelativeLayout.BELOW ,imageId-1);
}
menuImage.setLayoutParams(lp);
ImageView arrow = new ImageView(this);
arrow.setImageResource(R.drawable.arrow_menu);
arrow.setPadding(0, 0, 15, 0);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT );
params.addRule(RelativeLayout.ALIGN_RIGHT,menuImage.getId());
params.addRule(RelativeLayout.CENTER_VERTICAL);
arrow.setLayoutParams(params);
container.addView(menuImage);
container.addView(arrow);
imageId++;
}
}
I think the line below is your problem
params.addRule(RelativeLayout.CENTER_VERTICAL);
YES, you are most likely adding multiple arrows, they are just simply one on top of each other ALL aligned to the vertical center of the full relative layout. That command is not performing a vertical centering against your button item, but agains the parent RelativeLayout.
My question is simple,
How to set my buttons layout_gravity programmatically?
I found this on internet, but it simply throws me a Nullpointer exception:
Button MyButton = new Button(this);
LinearLayout.LayoutParams lllp=(LinearLayout.LayoutParams)MyButton.getLayoutParams();
lllp.gravity=Gravity.RIGHT;
MyButton.setLayoutParams(lllp);
MyLinearLayout.addView(MyButton);
Any solution?
Java
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
params.weight = 1.0f;
params.gravity = Gravity.TOP;
button.setLayoutParams(params);
Kotlin
val params = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
weight = 1.0f
gravity = Gravity.TOP
}
For gravity values and how to set gravity check Gravity.
Basically, you should choose the LayoutParams depending on the parent. It can be RelativeLayout, LinearLayout etc...
I'd hate to be resurrecting old threads but this is a problem that is not answered correctly and moreover I've ran into this problem myself.
Here's the long bit, if you're only interested in the answer please scroll all the way down to the code:
android:gravity and android:layout_gravity works differently. Here's an article I've read that helped me.
GIST of article: gravity affects view after height/width is assigned. So gravity centre will not affect a view that is done FILL_PARENT (think of it as auto margin). layout_gravity centre WILL affect view that is FILL_PARENT (think of it as auto pad).
Basically, android:layout_gravity CANNOT be access programmatically, only android:gravity.
In the OP's case and my case, the accepted answer does not place the button vertically centre.
To improve on Karthi's answer:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
button.setLayoutParams(params);
Link to LinearLayout.LayoutParams.
android:layout_gravity shows "No related methods" meaning cannot be access programatically.
Whereas gravity is a field in the class.
I had a similar problem with programmatically setting layout_gravity on buttons in a GridLayout.
The trick was to set gravity on the button layoutParams AFTER the button was added to a parent (GridLayout), otherwise the gravity would be ignored.
grid.addView(button)
((GridLayout.LayoutParams)button.getLayoutParams()).setGravity(int)
MyButton.setGravity(Gravity.RIGHT);
For layout_gravity use the answer stated by "karthi". This method sets gravity to place the children inside the view.
layoutParams2.gravity = Gravity.RIGHT|Gravity.BOTTOM;
use this to add mor than one gravity
If you want to change the layou_gravity of an existing view do this:
((FrameLayout.LayoutParams) view.getLayoutParams()).gravity = Gravity.BOTTOM;
Remember to use the right LayoutParams based on the Layout type your view is in. Ex:
LinearLayout.LayoutParams
KOTLIN setting more than one gravity on FrameLayout without changing size:
// assign more than one gravity,Using the operator "or"
var gravity = Gravity.RIGHT or Gravity.CENTER_VERTICAL
// update gravity
(pagerContainer.layoutParams as FrameLayout.LayoutParams).gravity = gravity
// refresh layout
pagerContainer.requestLayout()
This question is old but I just had the same problem and solved it like this
LayoutParams lay = new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)
lay.gravity = Gravity.CENTER;
I use someting like that: (Xamarin and C# code)
LinearLayout linLayout= new LinearLayout(this);
linLayout.SetGravity(GravityFlags.Center);
TextView txtView= new TextView(this);
linLayout.AddView(txtView);
the SetGravity puts my textView in the center of the layout.
So SetGravity layout property refer to layout content
In case you need to set Gravity for a View use the following
Button b=new Button(Context);
b.setGravity(Gravity.CENTER);
For setting layout_gravity for the Button
use gravity field for the layoutparams as
LayoutParams lp=new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
lp.gravity=Gravity.CENTER;
try this
hope this clears
thanks
If you want to put a view in the center of parent, you can do with following code..
public class myLayout extends LinearLayout {
public myLayout(Context context) {
super(context);
RelativeLayout vi = (RelativeLayout) ((LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.activity_main, null);
LinearLayout.LayoutParams cc = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
cc.gravity = Gravity.CENTER;
this.setGravity(Gravity.CENTER);
this.addView(vi);
}
}
these code section make LinearLayout put the first view elements in the center of parent.
So, we system don't consider the initial width and high to arrange view in the center .
I do the code section well.
The rest of the answers are right, I want to add more explaination. The layout_gravity is about how to position the view in parent view.
You must set gravity **after method parentView.addView() ** was called. We can see the code:
public void setLayoutParams(ViewGroup.LayoutParams params) {
if (params == null) {
throw new NullPointerException("Layout parameters cannot be null");
}
mLayoutParams = params;
resolveLayoutParams();
if (mParent instanceof ViewGroup) {
((ViewGroup) mParent).onSetLayoutParams(this, params);
}
requestLayout();
}
And the problem of null pointer is because it's not calling addView before getLayoutParams().
The annotation was already said "This method may return null if this View is not attached to a parent ViewGroup or {#link#setLayoutParams(android.view.ViewGroup.LayoutParams)} was not invoked successfully. When a View is attached to a parent ViewGroup, this method must not return null."
to RelativeLayout, try this code , it works for me:
yourLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
Perfectly Working!!! None of the above answer works for me. In Xml file setting gravity and setting layout_gravity is different. Check out the below code
// here messageLL is the linear layout in the xml file
// Before adding any view just remove all views
messageLL.removeAllViews();
// FrameLayout is the parent for LinearLayout
FrameLayout.LayoutParams params = new
FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER|Gravity.CENTER_VERTICAL;
messageLL.setLayoutParams(params);
messageText.setVisibility(View.GONE);
messageNoText.setVisibility(View.VISIBLE);
messageLL.addView(messageNoText);
Also check This,where you can find clear explanation about gravity and layout_gravity .
Most of above answer are right, so written a helper methods, so you can use it
directly in you project .
set layout_gravity programmtically
// gravity types : Gravity.BOTTOM, Gravity.START etc.
// view : can be any view example : button, textview, linearlayout, image etc.
// for single view
public static void setLayoutGravity(int gravity, View view){
((LinearLayout.LayoutParams) view.getLayoutParams()).gravity = gravity;
}
// for mulitple views
public static void setLayoutGravity(int gravity, View ...view){
for(View item : view)
((LinearLayout.LayoutParams) item.getLayoutParams()).gravity = gravity;
}
Modify the existing layout params and set layout params again
//Get the current layout params and update the Gravity
(iv.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.START
//Set layout params again (this updates the view)
iv.layoutParams = layoutParams
I switched from LinearLayout.LayoutParams to RelativeLayout.LayoutParams to finally get the result I was desiring on a custom circleview I created.
But instead of gravity you use addRule
RelativeLayout.LayoutParams mCircleParams = new RelativeLayout.LayoutParams(circleheight,circleheight);
mCircleParams.addRule(RelativeLayout.CENTER_IN_PARENT);
int width=getResources().getDisplayMetrics().widthPixels;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams
(width, width);
params.gravity = Gravity.CENTER;
iv_main_text = new HTextView(getContext());
iv_main_text.setLayoutParams(params);
iv_main_text.setBackgroundColor(Color.BLUE);
iv_main_text.setTextSize(60);
iv_main_text.setGravity(Gravity.CENTER);
iv_main_text.setTextColor(Color.BLACK);
FloatingActionButton sendFab = new FloatingActionButton(this);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(32, 32, 32, 32);
layoutParams.gravity = Gravity.END|Gravity.BOTTOM;
sendFab.setLayoutParams(layoutParams);
sendFab.setImageResource(android.R.drawable.ic_menu_send);
Try this code
Button btn = new Button(YourActivity.this);
btn.setGravity(Gravity.CENTER | Gravity.TOP);
btn.setText("some text");
or
btn.setGravity(Gravity.TOP);