ConstraintLayout Center views between each other - android

How can I set the vertical centre of view1 to the vertical centre of view2 ???
val view1 = ConstraintLayout(context)
view1.layoutParams = ConstraintLayout.LayoutParams(100, 200)
view1.id = View.generateId()
val view2 = ConstraintLayout(context)
view2.layoutParams = ConstraintLayout.LayoutParams(50, 100)
view2.id = View.generateId()
layout.addView(view1)
lyout.addView(view2)
val cs = ConstraintSet()
cs.clone(layout)
//setting position of view1
cs.connect(view1.id, ConstraintSet.TOP, layout.paddingTop, ConstraintSet.TOP, 50)
cs.connect(view1.id, ConstraintSet.START, layout.paddingStart, ConstraintSet.START, 100)
//setting postion of view2
cs.connect() // ??? no option like "ConstraintSet.VERTICAL_CENTER"
cs.connect(view1.id, ConstraintSet.paddingEnd, view2.paddingStart, ConstraintSet.START, 100)
cs.applyTo(layout)
What should i write in ConstraintSet to achieve layout like this :
|------|
| | |---|
| | - - | |
| | |---|
|------|

Normally, you center a view by applying both top+bottom constraints (centered vertically) or start+end constraints (centered horiziontally) or both.
If you want view2 to be centered vertically with respect to view1, you could do that with two connect() calls:
cs.connect(view2.getId(), ConstraintSet.TOP, view1.getId(), ConstraintSet.TOP);
cs.connect(view2.getId(), ConstraintSet.BOTTOM, view1.getId(), ConstraintSet.BOTTOM);
Of course, there's also a convenience method you could use:
cs.centerVertically(view2.getId(), view1.getId());

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 add constraints to View in constraint layout

I'm creating TextViews programmatically and adding them to my constraint layout. They are by default placed in the top left corner. I want them to go below each other, the first one being below an EditText.
This is my code:
ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.cLayout);
ConstraintSet set = new ConstraintSet();
TextView tv = new TextView(this);
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT, // Width of TextView
ConstraintLayout.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(lp);
set.clone(layout);
set.connect(tv.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, 8);
set.connect(tv.getId(), ConstraintSet.TOP, editText.getId(), ConstraintSet.BOTTOM, 8);
tv.setId(View.generateViewId());
set.applyTo(layout);
layout.addView(tv,0);
As you see, I've already set a constraint from TOP of View to BOTTOM of editText. Still, it shows in the top left corner. Why is that?
Your code order isn't proper, the following code should work.
ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.cLayout);
TextView tv = new TextView(this);
tv.setText("Something");
tv.setId(View.generateViewId());
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT, // Width of TextView
ConstraintLayout.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(lp);
layout.addView(tv,0);
ConstraintSet set = new ConstraintSet();
set.clone(layout);
set.connect(tv.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, 8);
set.connect(tv.getId(), ConstraintSet.TOP, editText.getId(), ConstraintSet.BOTTOM, 8);
set.applyTo(layout);
P.S - I agree with Syed Ahmed Jamil that you should preferably use a RecyclerView or ListView, but it doesn't hurt to know how to set ConstraintLayout constraints properly.

Adding constraints to views programmatically using ConstraintSet does not give expected result in Android?

I have a custom ConstraintLayout, and there's a TextView inside of it. I'm doing everything programmatically WITHOUT XML at all, here's the code:
public class CustomView extends ConstraintLayout {
private TextView textView;
public CustomView(Context context) {
super(context);
textView = new TextView(context);
textView.setId(View.generateViewId());
textView.setText("...");
// Adding border to the view in order to visualize the frame
GradientDrawable border = new GradientDrawable();
border.setColor(Color.TRANSPARENT);
border.setStroke(1, Color.BLACK);
textView.setBackground(border);
addView(textView);
// Apply constraints to textView. Left = right = top = bottom = 120
ConstraintSet set = new ConstraintSet();
set.clone(this);
set.connect(textView.getId(), ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT, 120);
set.connect(textView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 120);
set.connect(textView.getId(), ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 120);
set.connect(textView.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 120);
set.applyTo(this);
}
}
When I run the above code, I'm getting some wrong results:
If the text in textView is short:
If the text in textView is long:
If I understand correct that your wrong result - you don't see the margins?
I think this because defaults layout_width layout_height of your textview - wrap_content. Defaults must be 0dp.
Try like:
LayoutParams lp = new LayoutParams(0, 0);
textView.setLayoutParams(lp);

Changing ConstraintLayout children's margin and size programmatically

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.

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);

Categories

Resources