Changing ConstraintLayout children's margin and size programmatically - android

I'm writing a custom view to be able to use custom XML attributes to set a view's margin and size based on these attributes, everything worked fine until i got to the part where children of ConstraintLayout get's their margins and size determined by custom values.
The margins doesn't make any difference and the view stays on the top left corner of its parent ConstraintLayout.
What could be the problem? (The Image should be 500PXs away from the screen boundaries)
if (hasCustomWidth || hasCustomHeight || hasCustomTopMargin || hasCustomRightMargin || hasCustomBottomMargin || hasCustomLeftMargin) {
if(((ViewGroup)getParent()) instanceof LinearLayout) {
LinearLayout.LayoutParams newLayoutParams = new LinearLayout.LayoutParams((int) Math.round(customWidth), (int) Math.round(customHeight));
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) newLayoutParams;
marginLayoutParams.setMargins((int) Math.round(customLeftMargin), (int) Math.round(customTopMargin), (int) Math.round(customRightMargin), (int) Math.round(customBottomMargin));
setLayoutParams(newLayoutParams);
} else if(((ViewGroup)getParent()) instanceof ConstraintLayout) {
ConstraintLayout parentConstraintLayout = (ConstraintLayout)CustomAppCompatImageView.this.getParent();
ConstraintLayout.LayoutParams newLayoutParams = new ConstraintLayout.LayoutParams((int) Math.round(customWidth), (int) Math.round(customHeight));
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(parentConstraintLayout);
constraintSet.connect(CustomAppCompatImageView.this.getId(), ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT, 500);
constraintSet.setMargin(CustomAppCompatImageView.this.getId(), ConstraintSet.LEFT, 500);
setLayoutParams(newLayoutParams);
constraintSet.applyTo(parentConstraintLayout);
parentConstraintLayout.invalidate();
} else {
throw new RuntimeException("no listed parent LayoutParams subclass!");
}
invalidate();
}
Result:

I found the solution: apparently Android doesn't take ConstraintSet.LEFT and ConstraintSet.RIGHT as proper arguments, and must be replaced with ConstraintSet.START and ConstraintSet.END.

Related

How do I add views dynamically through Kotlin code

So I need to add views to my constraint layout for each item in a list.
The code I have right now is:
for (i in 0..hikes.size - 1) {
var parentLayout = findViewById<ConstraintLayout>(R.id.RoutesOverview)
var constraintSet = ConstraintSet()
var view = View(this)
view.id = i
var params = ConstraintLayout.LayoutParams (
LayoutParams.MATCH_PARENT,
700
)
params.setMargins(48, 48, 48, 0)
view.setBackgroundColor(Color.parseColor("#81c27a"))
view.layoutParams = params
RoutesOverview.addView(view)
constraintSet.clone(parentLayout)
constraintSet.connect(view.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
constraintSet.connect(view.id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END)
constraintSet.connect(view.id, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START)
constraintSet.connect(view.id, ConstraintSet.TOP, prev.id, ConstraintSet.TOP)
constraintSet.applyTo(parentLayout)
prev = view
}
The RoutesOverview object is just the constraintLayout from my xml.
In the first iteration the prev object contains a view who is always there.
When trying this code, I see that the left and right margin gets set correctly, but the top doesn't nor get the second, third... view placed correctly.
The purpose of the views is actually just to use as a background for other textviews to get displayed on, I don't know if there's a better way to do this.

Programmatically set margin to ConstraintLayout

I need to change margin of toolbar, which was made of ConstraintLayout, in different cases. I tried to do it in following way
ConstraintLayout.LayoutParams newLayoutParams = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
ConstraintLayout.MarginLayoutParams layoutParams = new ConstraintLayout.MarginLayoutParams(newLayoutParams);
layoutParams.setMargins(0, 0, 0, 0);
toolbar.setLayoutParams(newLayoutParams);
but in second case layoutParams.setMargins(16, 16, 16, 16);
it did not change. So, can someone give other way or point to the mistake. Thanks for spending time to my problem.
I tried to use newLayoutParams.setMargins(54, 54, 54, 0); this puts margin to left and right, but I still need to put margin on top of it.
Finally with help of #Aksh I found my mistake and solve my problem. If someone find it useful, I will put my code bellow
ConstraintLayout.LayoutParams newLayoutParams = (ConstraintLayout.LayoutParams) toolbar.getLayoutParams();
newLayoutParams.topMargin = 0;
newLayoutParams.leftMargin = 0;
newLayoutParams.rightMargin = 0;
toolbar.setLayoutParams(newLayoutParams);
good way to add margin to a view in constraintlayout
val constraintSet = ConstraintSet()
constraintSet.clone(constraintLayoutId)
val marginTop = context.getDimension(10f)
constraintSet.setMargin(R.id.tv_user, ConstraintSet.TOP, marginTop)
constraintSet.applyTo(constraintLayoutId)
fun Context.getDimension(value: Float): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, value, this.resources.displayMetrics).toInt()
}
I once modified a ConstraintLayout with a ConstraintSet to change the elements it got linked with. I also changed the margin within that process which is the last parameter of the connect method:
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(layout);
constraintSet.connect(
R.id.layout_id,
ConstraintSet.START,
R.id.layout_id2,
ConstraintSet.END,
8);
constraintSet.applyTo(layout);
Maybe this gives you another hint to find a solution?
You might wanna try
ViewGroup.MarginLayoutParams params = yourConstraintLayout.getLayoutParams();
params.topMargin = x;
//others shows up in suggestion
I haven't tried it though I believe it should work as ConstraintLayout is a ViewGroup.
For layoutParams.setMargins(w, x, y, z) the reason it's not changing is because you're most likely treating the values as Dp's rather than Px's, for which the method accepts.
To get Px from the Dp, you want to use:
int pxValue = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());

How to add margin in dp on dynamically generated views in constraint layout

I have added 2 views from xml in constraint layout, Now i need to add new view below the view created from xml
This is what i do to add new view
//leftMargin calculation
int topMargin= Utils.pxToDp(20);
ImageView imageView = new ImageView(this);
imageView.setId(View.generateViewId());
constraintLayout.addView(imageView);
ConstraintSet set = new ConstraintSet();
set.clone(constraintLayout);
set.constrainWidth(imageView.getId(), ConstraintSet.MATCH_CONSTRAINT);
set.connect(imageView.getId(), ConstraintSet.TOP, eventsViewPager.getId(), ConstraintSet.BOTTOM, topMargin);
I am defining margin 20dp here, but it just adds a thin line over the view, and if i use margin around 400, then it gives me the desired result, there must be some mistake in conversion may be that i am making here.
This is how i convert values from px to dp
public static int pxToDp(int px){
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
I think you should convert DP to pixel and not viceversa, use TypedValue for that like this:
int marginTopDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20,
getResources().getDisplayMetrics());

Set ConstraintLayout width to match parent width programmatically

In an android application I am attempting to programmatically add customized ConstraintLayout views to a vertically oriented LinearLayout.
I set the LayoutParams to MATCH_PARENT for width and WRAP_CONTENT for height in the ConstraintLayouts. However, when I run the application the ConstraintView is all scrunched up and the content is overlapping. Below are some relevant snippets and a screenshot of my application. How do I go about correcting this issue?
public class ItemView extends ConstraintLayout {
LinearLayout linearButtons;
LinearLayout linearText;
public ItemView(Context context, String name, String price, ArrayList<String> guests,
ArrayList<String> checked, int id) {
...
addView(linearText);
addView(linearButtons);
set.clone(this);
set.connect(linearText.getId(), ConstraintSet.LEFT, this.getId(),
ConstraintSet.LEFT, 8);
set.connect(linearText.getId(), ConstraintSet.TOP, this.getId(),
ConstraintSet.TOP, 8);
set.connect(linearButtons.getId(), ConstraintSet.RIGHT, this.getId(),
ConstraintSet.RIGHT, 8);
set.connect(linearButtons.getId(), ConstraintSet.TOP, this.getId(),
ConstraintSet.TOP, 8);
}
elsewhere:
for (Item it:r.getItems()) {
ItemView itemView = new ItemView(this, it.getName(), nf.format(it.getPrice()), dinerlist, it.getGuests(), i);
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT);
itemView.setLayoutParams(params);
vg.addV[enter image description here][1]iew(itemView);
Log.d("ItemView Children: ", itemView.getWidth()+" "+itemView.getHeight());
In ConstraintLayout in xml when you want a "MATCH_PARENT" width, you have to set the width to 0dp and then set the layout_constraintWidth_default attribute to "spread"
Programmatically you can do the same:
a) set a 0 dp width and height
b) set defaultWidth and defaultHeight constraints
//add the view with 0dp width and height
val layoutParams = ConstraintLayout.LayoutParams(0, 0)
val view = View(context)
view.layoutParams = layoutParams
view.id = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) View.generateViewId() else R.id.yourLayoutId
parent.addView(view)
//apply the default width and height constraints in code
val constraints = ConstraintSet()
constraints.clone(parent)
constraints.constrainDefaultHeight(view.id, ConstraintSet.MATCH_CONSTRAINT_SPREAD)
constraints.constrainDefaultWidth(view.id, ConstraintSet.MATCH_CONSTRAINT_SPREAD)
constraints.applyTo(parent)
If you need Java:
//add the view with 0dp width and height
ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(0, 0);
View view = View(context);
view.setLayoutParams(layoutParams);
view.setId(R.id.yourLayoutId);
parent.addView(view);
//apply the default width and height constraints in code
ConstraintSet constraints = new ConstraintSet();
constraints.clone(parent);
constraints.constrainDefaultHeight(view.getId(), ConstraintSet.MATCH_CONSTRAINT_SPREAD);
constraints.constrainDefaultWidth(view.getId(), ConstraintSet.MATCH_CONSTRAINT_SPREAD);
constraints.applyTo(parent);

Set GestureOverlayView width and height programmatically?

How can I set an GestureOverlayView's width and height programmatically?
I tried the below code. But I am getting null pointer exception in setting the width and height.
GestureOverlayView gestureOverlayView = new GestureOverlayView(this);
View inflate = getLayoutInflater().inflate(R.layout.main, null);
ImageView imageView = (ImageView) inflate.findViewById(R.id.imageView);
gestureOverlayView.addView(inflate);
gestureOverlayView.getLayoutParams().height = 50;
gestureOverlayView.getLayoutParams().width = 50;
setContentView(gestureOverlayView);
You need to add the view first before you can read out the height and width. Also then you meight get some trouble only after the second or third call of onMeasure(...) the dimensions are final.
If you want to set the width and height by code use this:
ViewGroup.LayoutParams lp = gestureOverlayView.getLayoutParams();
if(lp == null) {
// not yet added to parent
lp = new ViewGroup.LayoutParams(desiredWidth, desiredHeight);
} else {
lp.width = desiredWidth;
lp.height = desiredHeight;
}
gestureOverlayView.setLayoutParams(lp);
yourparent.addView(gestureOverlayView, lp);
Please note that you need to choose also the right LayoutParams implementation. Here I use that one of ViewGroup.

Categories

Resources