Android center view with SetMargins programmatically? [duplicate] - java

I want to add an unknown number of ImageView views to my layout with margin. In XML, I can use layout_margin like this:
<ImageView android:layout_margin="5dip" android:src="#drawable/image" />
There is ImageView.setPadding(), but no ImageView.setMargin(). I think it's along the lines of ImageView.setLayoutParams(LayoutParams), but not sure what to feed into that.
Does anyone know?

android.view.ViewGroup.MarginLayoutParams has a method setMargins(left, top, right, bottom). Direct subclasses are: FrameLayout.LayoutParams, LinearLayout.LayoutParams and RelativeLayout.LayoutParams.
Using e.g. LinearLayout:
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(left, top, right, bottom);
imageView.setLayoutParams(lp);
MarginLayoutParams
This sets the margins in pixels. To scale it use
context.getResources().getDisplayMetrics().density
DisplayMetrics

image = (ImageView) findViewById(R.id.imageID);
MarginLayoutParams marginParams = new MarginLayoutParams(image.getLayoutParams());
marginParams.setMargins(left_margin, top_margin, right_margin, bottom_margin);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams);
image.setLayoutParams(layoutParams);

All the above examples will actually REPLACE any params already present for the View, which may not be desired. The below code will just extend the existing params, without replacing them:
ImageView myImage = (ImageView) findViewById(R.id.image_view);
MarginLayoutParams marginParams = (MarginLayoutParams) image.getLayoutParams();
marginParams.setMargins(left, top, right, bottom);

Kevin's code creates redundant MarginLayoutParams object. Simpler version:
ImageView image = (ImageView) findViewById(R.id.main_image);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(image.getLayoutParams());
lp.setMargins(50, 100, 0, 0);
image.setLayoutParams(lp);

If you want to change imageview margin but leave all other margins intact.
Get MarginLayoutParameters of your image view in this case: myImageView
MarginLayoutParams marginParams = (MarginLayoutParams) myImageView.getLayoutParams();
Now just change the margin you want to change but leave the others as they are:
marginParams.setMargins(marginParams.leftMargin,
marginParams.topMargin,
150, //notice only changing right margin
marginParams.bottomMargin);

I use simply this and works great:
ImageView imageView = (ImageView) findViewById(R.id.image_id);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
layoutParams.setMargins(left, top, right, bottom);
imageView.setLayoutParams(layoutParams);
setMargins()'s unit is pixel not dp. If you want to set margin in dp, just inside your values/dimens.xml file create your dimensions like:
<resources>
<dimen name="right">16dp</dimen>
<dimen name="left">16dp</dimen>
</resources>
and access like:
getResources().getDimension(R.dimen.right);

If you use kotlin, this can be simplified by creating an extension function
fun View.setMarginExtensionFunction(left: Int, top: Int, right: Int, bottom: Int) {
val params = layoutParams as ViewGroup.MarginLayoutParams
params.setMargins(left, top, right, bottom)
layoutParams = params
}
Now all you need is a view, and this extension function can be used anywhere.
val imageView = findViewById(R.id.imageView)
imageView.setMarginExtensionFunction(0, 0, 0, 0)

You can use this method, in case you want to specify margins in dp:
private void addMarginsInDp(View view, int leftInDp, int topInDp, int rightInDp, int bottomInDp) {
DisplayMetrics dm = view.getResources().getDisplayMetrics();
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.setMargins(convertDpToPx(leftInDp, dm), convertDpToPx(topInDp, dm), convertDpToPx(rightInDp, dm), convertDpToPx(bottomInDp, dm));
view.setLayoutParams(lp);
}
private int convertDpToPx(int dp, DisplayMetrics displayMetrics) {
float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics);
return Math.round(pixels);
}

Answer from 2020 year :
dependencies {
implementation "androidx.core:core-ktx:1.2.0"
}
and cal it simply in your code
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(5)
}

create layout dynamically and set its parameter as setmargin() will not work directly on an imageView
ImageView im;
im = (ImageView) findViewById(R.id.your_image_in_XML_by_id);
RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(im.getLayoutParams());
layout.setMargins(counter*27, 0, 0, 0);//left,right,top,bottom
im.setLayoutParams(layout);
im.setImageResource(R.drawable.yourimage)

For me this worked:
int imgCarMarginRightPx = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, definedValueInDp, res.getDisplayMetrics());
MarginLayoutParams lp = (MarginLayoutParams) imgCar.getLayoutParams();
lp.setMargins(0,0,imgCarMarginRightPx,0);
imgCar.setLayoutParams(lp);

sample code is here ,its very easy
LayoutParams params1 = (LayoutParams)twoLetter.getLayoutParams();//twoletter-imageview
params1.height = 70;
params1.setMargins(0, 210, 0, 0);//top margin -210 here
twoLetter.setLayoutParams(params1);//setting layout params
twoLetter.setImageResource(R.drawable.oo);

In Kotlin you can write it in more pleasant way
myView.layoutParams = LinearLayout.LayoutParams(
RadioGroup.LayoutParams.MATCH_PARENT, RadioGroup.LayoutParams.WRAP_CONTENT
).apply {
setMargins(12, 12, 12, 12)
}

Using a method similar to this might save you some headaches in some situations.
If you have two passes of programmatical tinkering with margins it is safer to check if there are already some layoutParams set. If there are some margins already one should increase them and not replace them:
public void addMargins(View v, int left, int top, int right, int bottom) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) v.getLayoutParams();
if (params == null)
params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
int oldLeft = params.leftMargin;
int oldTop = params.topMargin;
int oldRight = params.rightMargin;
int oldBottom = params.bottomMargin;
params.setMargins(oldLeft + left, oldTop + top, oldRight + right, oldBottom + bottom);
v.setLayoutParams(params);
}

Here is an example to add 8px Margin on left, top, right, bottom.
ImageView imageView = new ImageView(getApplicationContext());
ViewGroup.MarginLayoutParams marginLayoutParams = new ViewGroup.MarginLayoutParams(
ViewGroup.MarginLayoutParams.MATCH_PARENT,
ViewGroup.MarginLayoutParams.WRAP_CONTENT
);
marginLayoutParams.setMargins(8, 8, 8, 8);
imageView.setLayoutParams(marginLayoutParams);

We can create Linear LayoutParams & use resources.getDimensionPixelSize for dp value.
val mContext = parent.context
val mImageView = AppCompatImageView(mContext)
mImageView.setBackgroundResource(R.drawable.payment_method_selector)
val height = mContext.resources.getDimensionPixelSize(R.dimen.payment_logo_height)
val width = mContext.resources.getDimensionPixelSize(R.dimen.payment_logo_width)
val padding = mContext.resources.getDimensionPixelSize(R.dimen.spacing_small_tiny)
val margin = mContext.resources.getDimensionPixelSize(R.dimen.spacing_small)
mImageView.layoutParams = LinearLayout.LayoutParams(width, height).apply {
setMargins(margin, margin, 0, 0)
}
mImageView.setPadding(padding, padding, padding, padding)

Related

Set a view's width to be relative to device screen programmatically

I have a horizontal RecyclerView with child elements which I want to change the width of to be a bit less than the current match_parent set via the layout. I want to do this so that the next element in list is a bit visible on screen.
In the adapter onCreateViewHolder I am doing this:
ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = MainActivity.deviceWidth - (int) MainActivity.dpToPx(40.0f);
view.setLayoutParams(params);
where MainActivity.deviceWidth is:
DisplayMetrics displaymetrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
deviceWidth = displaymetrics.widthPixels;
screenDensity = Resources.getSystem().getDisplayMetrics().density;
and dpToPx is this function:
public static float dpToPx(float dp) {
return (dp * screenDensity + 0.5f);
}
This works. however, I noticed that on different devices, the "margin" I am setting is not always the same. I.e. the next card in the RecyclerView is not always showing the same amount.
Is the dpToPx conversion correct? I might be missing something else in my calculation but I am not sure what.
Update
Changing:
params.width = MainActivity.deviceWidth - (int) MainActivity.dpToPx(40.0f);
To:
params.width = (int) (MainActivity.deviceWidth *0.9);
works!. I am fine with this solution. I just want to know why the previous one does not work...

Android sliding tabs - set width of tabs programmatically

With my sliding tabs project, how can I programmatically set the width of the tabs so that they use the whole space of the sliding tab strip and are each equal in width size? I've tried using the code below but the tabs won't stretch as desired.
SlidingTabLayout.java
protected TextView createDefaultTabView(Context context) {
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setTextColor(context.getResources().getColor(R.color.black));
textView.setWidth(0);
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
textView.setPadding(padding, padding, padding, padding);
return textView;
}
Text weight error
Add this in your method
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
textView.setWidth(size.x / count); // Where count is number of textviews
Also if you are supporting older version
Use this
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2)
{
display.getSize(size);
}
else
{
size.set(display.getWidth(), display.getHeight());
}
In a update these you can now use,
mSlidingTabLayout.setDistributeEvenly(true);
within the onViewCeated,
More can be found here.
I have a different problem, wherein I had to customize each of the tabs' width:
I was using setDistributeEvenly function. Instead I needed to set each of the textviews' weight.
Add this variable on your SlidingTabLayout.java:
private int[] mTabWeights;
This method should set the tab weights:
public void setTabWeights(int[] weights){
mTabWeights = weights;
}
Look for the method populateTabStrip() and add an else statement:
if (mDistributeEvenly) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
lp.width = 0;
lp.weight = 1;
}else{
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
lp.width = 0;
lp.weight = mTabWeights[i];
}
You can refactor the code to make it cleaner. Here it is when used:
stNews = (SlidingTabLayout) findViewById(R.id.stNews);
stNews.setDistributeEvenly(false);
stNews.setTabWeights(new int[]{2,3,3});
Here's the end result:
Hope it helps!

Modify margin params in code [duplicate]

Can this attribute be changed dynamically in Java code?
android:layout_marginRight
I have a TextView, that has to change its position some pixels to the left dynamically.
How to do it programmatically?
EDIT: A more generic way of doing this that doesn't rely on the layout type (other than that it is a layout type which supports margins):
public static void setMargins (View v, int l, int t, int r, int b) {
if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
p.setMargins(l, t, r, b);
v.requestLayout();
}
}
You should check the docs for TextView. Basically, you'll want to get the TextView's LayoutParams object, and modify the margins, then set it back to the TextView. Assuming it's in a LinearLayout, try something like this:
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);
I can't test it right now, so my casting may be off by a bit, but the LayoutParams are what need to be modified to change the margin.
NOTE
Don't forget that if your TextView is inside, for example, a
RelativeLayout, one should use RelativeLayout.LayoutParams instead of
LinearLayout.LayoutParams
Update: Android KTX
The Core KTX module provides extensions for common libraries that are part of the Android framework, androidx.core.view among them.
dependencies {
implementation "androidx.core:core-ktx:{latest-version}"
}
The following extension functions are handy to deal with margins:
Note: they are all extension functions of MarginLayoutParams, so
first you need to get and cast the layoutParams of your view:
val params = (myView.layoutParams as ViewGroup.MarginLayoutParams)
setMargins() extension function:
Sets the margins of all axes in the ViewGroup's MarginLayoutParams. (The dimension has to be provided in pixels, see the last section if you want to work with dp)
inline fun MarginLayoutParams.setMargins(#Px size: Int): Unit
// E.g. 16px margins
params.setMargins(16)
updateMargins() extension function:
Updates the margins in the ViewGroup's ViewGroup.MarginLayoutParams.
inline fun MarginLayoutParams.updateMargins(
#Px left: Int = leftMargin,
#Px top: Int = topMargin,
#Px right: Int = rightMargin,
#Px bottom: Int = bottomMargin
): Unit
// Example: 8px left margin
params.updateMargins(left = 8)
updateMarginsRelative() extension function:
Updates the relative margins in the ViewGroup's MarginLayoutParams (start/end instead of left/right).
inline fun MarginLayoutParams.updateMarginsRelative(
#Px start: Int = marginStart,
#Px top: Int = topMargin,
#Px end: Int = marginEnd,
#Px bottom: Int = bottomMargin
): Unit
// E.g: 8px start margin
params.updateMargins(start = 8)
The following extension properties are handy to get the current margins:
inline val View.marginBottom: Int
inline val View.marginEnd: Int
inline val View.marginLeft: Int
inline val View.marginRight: Int
inline val View.marginStart: Int
inline val View.marginTop: Int
// E.g: get margin bottom
val bottomPx = myView1.marginBottom
Using dp instead of px:
If you want to work with dp (density-independent pixels) instead of px, you will need to convert them first. You can easily do that with the following extension property:
val Int.px: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
Then you can call the previous extension functions like:
params.updateMargins(start = 16.px, end = 16.px, top = 8.px, bottom = 8.px)
val bottomDp = myView1.marginBottom.dp
Old answer:
In Kotlin you can declare an extension function like:
fun View.setMargins(
leftMarginDp: Int? = null,
topMarginDp: Int? = null,
rightMarginDp: Int? = null,
bottomMarginDp: Int? = null
) {
if (layoutParams is ViewGroup.MarginLayoutParams) {
val params = layoutParams as ViewGroup.MarginLayoutParams
leftMarginDp?.run { params.leftMargin = this.dpToPx(context) }
topMarginDp?.run { params.topMargin = this.dpToPx(context) }
rightMarginDp?.run { params.rightMargin = this.dpToPx(context) }
bottomMarginDp?.run { params.bottomMargin = this.dpToPx(context) }
requestLayout()
}
}
fun Int.dpToPx(context: Context): Int {
val metrics = context.resources.displayMetrics
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), metrics).toInt()
}
Then you can call it like:
myView1.setMargins(8, 16, 34, 42)
Or:
myView2.setMargins(topMarginDp = 8)
Use LayoutParams (as explained already). However be careful which LayoutParams to choose. According to https://stackoverflow.com/a/11971553/3184778 "you need to use the one that relates to the PARENT of the view you're working on, not the actual view"
If for example the TextView is inside a TableRow, then you need to use TableRow.LayoutParams instead of RelativeLayout or LinearLayout
Use This function to set all Type of margins
public void setViewMargins(Context con, ViewGroup.LayoutParams params,
int left, int top , int right, int bottom, View view) {
final float scale = con.getResources().getDisplayMetrics().density;
// convert the DP into pixel
int pixel_left = (int) (left * scale + 0.5f);
int pixel_top = (int) (top * scale + 0.5f);
int pixel_right = (int) (right * scale + 0.5f);
int pixel_bottom = (int) (bottom * scale + 0.5f);
ViewGroup.MarginLayoutParams s = (ViewGroup.MarginLayoutParams) params;
s.setMargins(pixel_left, pixel_top, pixel_right, pixel_bottom);
view.setLayoutParams(params);
}

ImageView disappears after LayoutParams Change

I added a ImageView to my LinearLayout in the onCreate method programmatically and it worked as it should.
img = new ImageView(this);
img.setImageResource(R.drawable.source);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(0, 50, 0, 0);
img.setLayoutParams(params);
layout = (LinearLayout) findViewById(R.id.index_view);
layout.addView(img);
And the I want to change it's x and y coordinates when the user touches the screen.
onTouch method - case ACTION_MOVE:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(newX, newY, 0, 0);
img.setLayoutParams(params);
the newX and newY are calculated based on the users touch-coordinates
But this code doesn't seem to work correctly.
I created toasts to show me the Image width after every touch and it showed me that the width is set to zero after first touch. This tells me: ImageView disappeared.
Any guesses?
I am assuming that you made sure that you are getting newX, newY values in onTouch().
I feel that your aim is to edit the Layout parameters but instead of doing that what you are doing is, you are assigning a new set of parameters with width and height as LayoutParams.WRAP_CONTENT and then setting the margins.
You might try to first get the existing parameters as follows:
LinearLayout.LayoutParams params =
( LinearLayout.LayoutParams) img.getLayoutParams();
Then change the margin:
params.setMargins(newX, newY, 0, 0);
img.setLayoutParams(params);
Try it and notify if it helps. If not then we can talk further.

setMargins() won't work - Android

I've been looking for solutions for this problem for more than one hour now, but none is working. :/
I want to set the top margin of my TextView to a value depending on the integer position.
But somehow the margins won't show up...
public void addElements(int position, String title,int colour, RelativeLayout ld){
int px = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
1,
res.getDisplayMetrics()
);
int pos = 168*px;
LayoutParams params;
params = new LayoutParams(LayoutParams.MATCH_PARENT,144*px);
params.setMargins(0, 168, 0, 0);
TextView tv = new TextView(activity);
tv.requestLayout();
tv.setBackgroundResource(colour);
tv.setText(title);
tv.setSingleLine(false);
ld.addView(tv, params);
}
Try this:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 144);
params.setMargins(0, 168, 0, 0);
LayoutMargins are reserved for ViewGroup's such as RelativeLayout, LinearLayout, etc. Most common Views such as a TextView use padding in order to add additional spacing.
This should work:
tv.setPaddingRelative(0,168,0,0);

Categories