I cannot get margins to work correctly when using a ConstraintSet
ConstraintSet constraintSet = new ConstraintSet();
ConstraintLayout constraintLayout = (ConstraintLayout) LayoutInflater.from(this).inflate(R.layout.activity_main, null);
constraintSet.clone(constraintLayout);
// START WORKS
//constraintSet.connect(R.id.text, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, 50);
// LEFT DOES NOT
constraintSet.connect(R.id.text, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT, 50);
constraintSet.connect(R.id.text, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 50);
constraintSet.connect(R.id.text, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 50);
constraintSet.connect(R.id.text, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 50);
constraintSet.applyTo(constraintLayout);
There's a small sample app there if anyone wants to reproduce: https://github.com/martinbonnin/TestConstraintLayout/tree/master
Anyone knows what I'm missing ?
I am not sure what you are trying to do. What is your expected result.
But...
You are using END and LEFT which is a little strange.
normally you would use START&END or LEFT&RIGHT
Related
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.
Now,here is my question.
how can I use ConstraintSet's connect to set attr like 'app:layout_constraintBottom_toBottomOf="parent"'
Try this
TextView textView = new TextView(this);
textView.setId(R.id.text_id);
ConstraintSet set = new ConstraintSet();
set.clone(constraintLayout);
set.connect(textView.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 0);
constraintLayout.addView(textView);
set.applyTo(constraintLayout);
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.
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);
lately i always got to a point where i want to create my UI dynamically.
I found a way to do so but i dont really like it.
For example i wanted to create a GoogleCalender like Dayview and ended up doing like so: (don't read the code in detail just see that it's bad)
constraintSet = new ConstraintSet();
View nextHolder = new View(this);
View nextMarker = new View(this);
TextView nextTime = new TextView(this);
holders[i] = nextHolder;
times[i] = nextTime;
markers[i] = nextMarker;
int calcHour = hour + i;
if (calcHour < 10) {
nextTime.setText("0" + Integer.toString(calcHour) + ":00");
} else {
nextTime.setText(Integer.toString(calcHour) + ":00");
}
nextTime.setTextColor(0xFF000000);
nextMarker.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.grey, null));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
holders[i].setId(Utils.generateViewId());
markers[i].setId(Utils.generateViewId());
times[i].setId(Utils.generateViewId());
} else {
holders[i].setId(View.generateViewId());
markers[i].setId(View.generateViewId());
times[i].setId(View.generateViewId());
}
int nextHolderID = holders[i].getId();
int nextMarkerID = markers[i].getId();
int nextTimeID = nextTime.getId();
constraintLayout.addView(holders[i]);
constraintLayout.addView(markers[i]);
constraintLayout.addView(times[i]);
constraintSet.clone(constraintLayout);
//Constraint the Time-Stamp-Holders
constraintSet.constrainHeight(nextHolderID, Utils.convertDpToPixel(40, context));
constraintSet.constrainWidth(nextHolderID, ConstraintSet.MATCH_CONSTRAINT);
constraintSet.connect(nextHolderID, ConstraintSet.START, ConstraintSet.PARENT_ID,
ConstraintSet.START);
constraintSet.connect(nextHolderID, ConstraintSet.END, ConstraintSet.PARENT_ID,
ConstraintSet.END);
if (i == 1) {
constraintSet.connect(nextHolderID, ConstraintSet.TOP, startHolder.getId(),
ConstraintSet.BOTTOM, Utils.convertDpToPixel(8, context));
} else {
constraintSet.connect(nextHolderID, ConstraintSet.TOP, holders[i - 1].getId(),
ConstraintSet.BOTTOM, Utils.convertDpToPixel(8, context));
}
//Constraint the Time TextViews
constraintSet.constrainHeight(nextTimeID, ConstraintSet.WRAP_CONTENT);
constraintSet.constrainWidth(nextTimeID, ConstraintSet.WRAP_CONTENT);
constraintSet.connect(nextTimeID, ConstraintSet.BOTTOM, nextHolderID,
ConstraintSet.BOTTOM, Utils.convertDpToPixel(8, context));
constraintSet.connect(nextTimeID, ConstraintSet.TOP, nextHolderID,
ConstraintSet.TOP, Utils.convertDpToPixel(8, context));
constraintSet.connect(nextTimeID, ConstraintSet.START, nextHolderID,
ConstraintSet.START, Utils.convertDpToPixel(16, context));
//Constraint the timeline Views
constraintSet.constrainHeight(nextMarkerID, ConstraintSet.MATCH_CONSTRAINT);
constraintSet.constrainWidth(nextMarkerID, ConstraintSet.MATCH_CONSTRAINT);
constraintSet.connect(nextMarkerID, ConstraintSet.BOTTOM, nextTimeID,
ConstraintSet.BOTTOM, Utils.convertDpToPixel(8, context));
constraintSet.connect(nextMarkerID, ConstraintSet.TOP, nextTimeID,
ConstraintSet.TOP, Utils.convertDpToPixel(8, context));
constraintSet.connect(nextMarkerID, ConstraintSet.START, nextTimeID,
ConstraintSet.END, Utils.convertDpToPixel(16, context));
constraintSet.connect(nextMarkerID, ConstraintSet.END, nextHolderID,
ConstraintSet.END, Utils.convertDpToPixel(16, context));
constraintSet.applyTo(constraintLayout);
It's ugly and not performant.
So what i want to create now is a match history:
I would have a view that holds a match with 2 textViews for each teamname and 1 textView for the score. Those arrows should show how they would be placed in a constraint layout.
My guess how it should be done would be to create a layout.xml for the MatchView and in that xml i have a placeholder for the other textViews which i than can change programmatically. This layout.xml would be then used by my MatchView class and an object of my MatchView class is one MatchView.
For example:
MatchView matchView = new MatchView("Team1", "Team2", "score")
And the MatchView class would look like this:
public class MatchView {
MatchView.setLayout(match_view.xml);
TextView team1 = findViewById(team1TXT);
TextView team2 ...
//For the first view
MatchView(String team1, String team2, String score){
team1.setText(team1);
//...
constrain.toParent();
}
//For every following view
MatchView(String team1, String team2, String score, MatchView parentMatchView){
team1.setText(team1);
//...
constrain.toView(parentMatchView);
}
}
Is this the way how it's done? Are there more convenient ways?
If i guessed write do you have me a tutorial where they show how you really do it?
I searched for many days but i don't find what im really looking for.
I hope I'm not asking something too stupid.
Thanks in advance and greetings
Bolle