How to set gravity in programmingcally in a relativelayout. I have a XML layout with name chat_viewer_message.xml as below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="4dip"
android:paddingBottom="4dip"
android:gravity="left"
android:background="#drawable/chat_bg_in">
<ImageView
android:id="#+id/avatar"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_marginLeft="4dip"
android:src="#drawable/avatar_1_1"
/>
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/avatar"
android:paddingLeft="4dip"
/>
</RelativeLayout>
And code view in programming is as below:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final int type = getItemViewType(position);
final View view;
if (convertView == null) {
final int resource = R.layout.chat_viewer_message;
view = activity.getLayoutInflater()
.inflate(resource, parent, false);
if (type == TYPE_MESSAGE)
((TextView) view.findViewById(R.id.text)).setTextAppearance(
activity, appearanceStyle);
} else
view = convertView;
final MessageItem messageItem = (MessageItem) getItem(position);
String name;
final String account = messageItem.getChat().getAccount();
final String user = messageItem.getChat().getUser();
final String resource = messageItem.getResource();
final boolean incoming = messageItem.isIncoming();
final String server_host = view.getResources().getString(
R.string.server_host);
if (isMUC) {
name = resource;
}
if (incoming) {
view.setBackgroundResource(R.drawable.chat_bg_in);
} else {
// I WANT TO GRAVITY TO RIGHT. HOW TO CODE? THANKS
view.setBackgroundResource(R.drawable.chat_bg_out);
}
return view;
}
See gravity at the relativelayout with id = background, the default gravity is LEFT, So I want to if !incoming the value gravity at relativelayout be RIGHT instead LEFT.
Thanks.
Cast view to container layout, in this case RelativeLayout, and use setGravity(int) on it:
if (incoming) {
view.setBackgroundResource(R.drawable.chat_bg_in);
} else {
// I WANT TO GRAVITY TO RIGHT. HOW TO CODE? THANKS
view.setBackgroundResource(R.drawable.chat_bg_out);
((RelativeLayout) view).setGravity(Gravity.RIGHT);
}
A word of caution (from the docs):
Note that since RelativeLayout considers the positioning of each child
relative to one another to be significant, setting gravity will affect
the positioning of all children as a single unit within the parent.
This happens after children have been relatively positioned.
There are two main ways to programmatically set the gravity in a RelativeLayout. You can either set the gravity for all child views (setGravity(int)) or set the gravity individually (params.addRule(int)). Note: These methods are not available for LinearLayouts.
To set the gravity for all children:
RelativeLayout relativeLayout = findViewById(R.id.myRelativeLaout);
relativeLayout.setGravity(Gravity.CENTER);
To set the gravity for a single view within a RelativeLayout:
MyView myView = findViewById(R.id.myView);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
myView.setLayoutParams(params);
Sources:
RelativeLayout.setGravity(int)
RelativeLayout.LayoutParams.addRule(int)
RelativeLayout.LayoutParams.removeRule(int)
It works perfectly for my case:
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.topMargin = 700;//in my case
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);//in my case
varButton.setLayoutParams(layoutParams);
You can use:
RelativeLayout.LayoutParams paramas = new RelativeLayout.LayoutParams();
params.gravity = Gravity.RIGHT;
view.setLayoutParams(params);
For more info about gravity parameters u can check this: Gravity
Use method, setGravity(int)
http://developer.android.com/reference/android/widget/RelativeLayout.html#setGravity(int)
It's better way to set child's gravity by using RelativeLayout.LayoutParams.
See this.
How to programmatically set the layout_align_parent_right attribute of a Button in Relative Layout?
Building up chat layout and manipulating it programmatically &
sDirectionHasmap contains direction of each message.
if (sDirectionHashMap.get(idsList.get(position)).equals("incoming")) {
holder.messageLayout.setGravity(Gravity.LEFT);
} else {
holder.messageLayout.setGravity(Gravity.RIGHT);
}
Related
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 have a view (Linearlayout) inside a ConstraintLayout with the following attributes:
android:id="#+id/myView"
app:layout_constraintTop_toBottomOf="#+id/anotherView"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
At some occasions I wish to align myView to the left, by simply removing the right constraint. however I'm not able to do so.
I tried to use the following, simply to copy and apply the constraint parameters:
ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(holder.myView.getLayoutParams());
holder.myView.setLayoutParams(layoutParams);
but the layoutParams always receives an empty parameters set,and sends the view to the top left corner. Perhaps it's because I'm using this inside of a recyclerView?
How it looks inside the recyclerView:
public void onBindViewHolder(final RecyclerView.ViewHolder basicHolder, int position) {
ProfileAdapter.UserInfoViewHolder holder = (ProfileAdapter.UserInfoViewHolder) basicHolder;
ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(holder.myView.getLayoutParams());
holder.myView.setLayoutParams(layoutParams);
}
There's a bug (will be fixed in the next release) when setting layout params the way you do it. In the meantime, you can do:
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) holder.myView.getLayoutParams();
layoutParams.rightToRight = ConstraintLayout.LayoutParams.UNSET;
holder.myView.setLayoutParams(layoutParams);
The same in Kotlin:
val layoutParams = view.layoutParams as ConstraintLayout.LayoutParams
layoutParams.bottomToBottom = ConstraintLayout.LayoutParams.UNSET
I have ListView which contains items containing a View and a TextView:
chat_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="90dp"
android:id="#+id/chat_message_wrapper"
xmlns:pixlui="http://schemas.android.com/apk/com.neopixl.pixlui">
<View
android:id="#+id/message_indicator"
android:layout_width="10dp"
android:layout_height="90dp"/>
<com.neopixl.pixlui.components.textview.TextView
android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/midnight_blue"
android:padding="14dp"
android:layout_centerVertical="true"/>
</RelativeLayout>
And this is getView() in my Adapter class:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.chat_item, null);
}
ChatMessageItem item = getItem(position);
if(item != null) {
TextView messageTextView = (TextView) view.findViewById(R.id.message);
ViewGroup messageWrapper = (ViewGroup) view.findViewById(R.id.chat_message_wrapper);
View messageIndicatorView = view.findViewById(R.id.message_indicator);
if(messageTextView != null) {
messageTextView.setText(String.valueOf(item.getMessage()));
RelativeLayout.LayoutParams textParams = (RelativeLayout.LayoutParams)messageTextView.getLayoutParams();
RelativeLayout.LayoutParams indicatorParams = new RelativeLayout.LayoutParams(10, ViewGroup.LayoutParams.MATCH_PARENT);
RelativeLayout.LayoutParams messageWrapperParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 90);
if(item.getSender() == ChatMessageItem.Sender.ME) {
textParams.addRule(RelativeLayout.LEFT_OF, R.id.message_indicator);
indicatorParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
messageIndicatorView.setBackgroundColor(getContext().getResources().getColor(R.color.light_blue));
}
else if(item.getSender() == ChatMessageItem.Sender.OTHER) {
textParams.addRule(RelativeLayout.RIGHT_OF, R.id.message);
indicatorParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
messageIndicatorView.setBackgroundColor(getContext().getResources().getColor(R.color.silver));
}
messageTextView.setLayoutParams(textParams);
messageIndicatorView.setLayoutParams(indicatorParams);
messageWrapper.setLayoutParams(messageWrapperParams);
}
}
return view;
}
I added the following line to at least keep the height of the items constant, which used to also change (which will probably give me problems later, as the content is dynamic, but ok..)
RelativeLayout.LayoutParams messageWrapperParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 90);
The problem is when I scroll up and down more and more text disappears. messageIndicatorView does not disappear though, only the text disappears. If I keep scrolling enough, all text will disappear. What am I doing wrong and how can I fix it? Thanks. (I know I must use a ViewHolder for better performance, but I will do that when this problem is fixed)
The problem is that as the ListView recycles and reuses the views, conflicting rules are added to the RelativeLayout.LayoutParams instances for the #id/message TextView. In particular this happens whenever a view for a "ME" message is reused for an "OTHER" message, or vice-versa.
RelativeLayout.LayoutParams keeps a list of rules (actually an array by verb, so that you cannot add, say, two LEFT_OF rules -- but any other combination is possible, including problematic ones).
The easiest solution is to use a new RelativeLayout.LayoutParams object each time, by changing this line:
RelativeLayout.LayoutParams textParams =
(RelativeLayout.LayoutParams)messageTextView.getLayoutParams();
into:
RelativeLayout.LayoutParams textParams =
new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
There are other solutions, such as having different actual layouts for each kind of ListView item (via getItemViewType()) but it's probably overkill in this case. However if the differences between the two kinds of views were greater, it might be worth considering.
I have made a customView for a .gif image support in android. I got success in that, but currently that view is aligned to the top left corner of my activity. I want it to be aligned to the center of my activity. Please tell me how can I do this.
My code is as below:
GifwebView view = new GifwebView(this, "file:///android_asset/p3.gif");
view.setBackgroundColor(Color.parseColor("#00000000"));
RelativeLayout rel = (RelativeLayout) findViewById(R.id.rl_pics);
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
rel.setBackgroundColor(Color.parseColor("#00000000"));
view.setLayoutParams(p);
rel.addView(view);
CustomView
public class GifwebView extends WebView {
public GifwebView(Context context, String path) {
super(context);
// TODO Auto-generated constructor stub
loadUrl(path);
}
}
Your activity main layout (RelativeLayout), it's height and width should be match_parent, so it will take the whole screen, and it's gravity should be set to center, so that the elements in it will be positioned to center of the screen.
XML:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rl_pics"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
</RelativeLayout>
Activity:
RelativeLayout rel = (RelativeLayout) findViewById(R.id.rl_pics);
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
GifwebView view = new GifwebView(this, "file:///android_asset/p3.gif");
view.setBackgroundColor(Color.parseColor("#00000000"));
view.setLayoutParams(p);
rel.addView(view);
p.addRule(RelativeLayout.CENTER_HORIZONTAL);
view.setGravity(Gravity.CENTER_VERTICAL);
This should work. Also if you want the activity to take the whole screen instead of the requiered for filling your content you should use match_parent instead of wrap_content.
edit: if your custom view doesn't implement the setGravity(int) method, you can do this instead:
p.addRule(RelativeLayout.CENTER_HORIZONTAL|RelativeLayout.CENTER_IN_PARENT, view.getId());
I have a TableLayout where I add dynamically TableRows. In each TableRow, I add a Button.
I just would like to add some space between my columns (which are my buttons) but I can't figure out how...
I've tried to change all the possible margins but it doesn't work :(
So maybe I made a mistake in my code where I inflate them from XML files:
private void createButtons(final CategoryBean parentCategory) {
final List<CategoryBean> categoryList = parentCategory.getCategoryList();
title.setText(parentCategory.getTitle());
// TODO à revoir
int i = 0;
TableRow tr = null;
Set<TableRow> trList = new LinkedHashSet<TableRow>();
for (final CategoryBean category : categoryList) {
TextView button = (TextView) inflater.inflate(R.layout.button_table_row_category, null);
button.setText(category.getTitle());
if (i % 2 == 0) {
tr = (TableRow) inflater.inflate(R.layout.table_row_category, null);
tr.addView(button);
} else {
tr.addView(button);
}
trList.add(tr);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
CategoryBean firstChild = category.getCategoryList() != null && !category.getCategoryList().isEmpty() ? category
.getCategoryList().get(0) : null;
if (firstChild != null && firstChild instanceof QuestionsBean) {
Intent intent = new Intent(CategoryActivity.this, QuestionsActivity.class);
intent.putExtra(MainActivity.CATEGORY, category);
startActivityForResult(intent, VisiteActivity.QUESTION_LIST_RETURN_CODE);
} else {
Intent intent = new Intent(CategoryActivity.this, CategoryActivity.class);
intent.putExtra(MainActivity.CATEGORY, category);
startActivityForResult(intent, VisiteActivity.CATEGORY_RETURN_CODE);
}
}
});
i++;
}
for (TableRow tableRow : trList) {
categoryLaout.addView(tableRow);
}
}
My button_table_row_category.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/buttonTableRowCategory"
style="#style/ButtonsTableRowCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/validate" />
My table_row_category.xml:
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tableRowCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="100dp"
android:gravity="center"
android:padding="5dp" >
</TableRow>
Thank you for your help.
In the case of a TableLayout, Buttons themselves are the columns. That means you have to advise the Buttons to keep some space inbetween. You can do this by using layout parameters. They are much easier to set in XML, but it also works programmatically. It's important that you always use the LayoutParam class of the parent layout of the element where you apply it - in this case the parent is a TableRow:
// Within createButtons():
android.widget.TableRow.LayoutParams p = new android.widget.TableRow.LayoutParams();
p.rightMargin = DisplayHelper.dpToPixel(10, getContext()); // right-margin = 10dp
button.setLayoutParams(p);
// DisplayHelper:
private static Float scale;
public static int dpToPixel(int dp, Context context) {
if (scale == null)
scale = context.getResources().getDisplayMetrics().density;
return (int) ((float) dp * scale);
}
Most dimension attributes in Android take pixels if you set them programmatically - therefore you should use something like my dpToPixel() method. Please, don't EVER use pixel values in Android! You will regret it later on.
If you don't want the rightmost button to have this margin, just check with an IF and don't add the LayoutParam on it.
Solution in XML:
To avoid the LayoutInflater erasing your XML-defined attributes, do this while inflating (taken from Layout params of loaded view are ignored):
View view = inflater.inflate( R.layout.item /* resource id */,
MyView.this /* parent */,
false /*attachToRoot*/);
Alternative: Use a GridView like so: Android: Simple GridView that displays text in the grids
Add Padding Right for a component in the table row component
<TableRow
android:id="#+id/tableRow1">
<TextView
android:id="#+id/textView1"
android:paddingRight="20dp" />
</TableRow>
Try android:layout_marginRight="6dp" this worked for me.
Try Using the setColumnStretchable function of the TableLayout. Give it a columnn index and set its stretchable property to true.
Eg. If you have 3 columns.
TableLayout tblLayout;
tblLayout.setColumnStretchable(0, true);
tblLayout.setColumnStretchable(1, true);
tblLayout.setColumnStretchable(2, true);
The above will give you equal spacing between all 3 columns of the tableLayout.