Android Studio How To Set Constraints And Use LayoutParams Dynamically - android

In my Android Application I want to create a bunch of ConstraintLayouts where each has for example an ImageView and a TextView in them.
Everything is created from code exept for one TableRow with which I will start out. My Problem ist that despite being able to set the margins via LayoutParams for the ConstraintLayout, the ImageView and the TextView do not change at all when I try to set the margins.
public fun generateAsset(tableRow: TableRow) {
// <android.support.constraint.ConstraintLayout
// android:layout_margin="4dp"
// android:background="#drawable/x32_tile_dark">
val clayout = ConstraintLayout(context)
tableRow.addView(clayout)
val cparams = clayout.layoutParams as TableRow.LayoutParams
cparams.setMargins(4, 4, 4, 4) // <--- Works correctly!
clayout.layoutParams = cparams
clayout.setBackgroundResource(R.drawable.x32_tile_dark)
// <ImageView
// android:layout_width="0dp"
// android:layout_height="60dp"
// android:layout_marginTop="8dp"
// app:srcCompat="#drawable/x256_spaceship_door_gray_blue" />
val iView = ImageView(context)
clayout.addView(iView)
val iparams = iView.layoutParams as ConstraintLayout.LayoutParams
iparams.width = ConstraintLayout.LayoutParams.MATCH_PARENT
iparams.height = 200
iparams.setMargins(8, 8, 8, 8) // <--- Does not do anything!
iView.layoutParams = iparams
iView.setImageResource(R.drawable.x256_spaceship_door_gray_blue)
// <TextView
// android:text="Massive Spaceship Door"
// android:layout_marginLeft="8dp"
// android:layout_marginRight="8dp"
// android:layout_marginBottom="4dp"
// android:textColor="#android:color/white" />
val ntext = TextView(context)
clayout.addView(ntext)
val nparams = ntext.layoutParams as ConstraintLayout.LayoutParams
nparams.setMargins(8, 8, 8, 8) // <--- Does not do anything!
ntext.layoutParams = nparams
ntext.setTextColor(Color.WHITE)
ntext.text = assetName
}
The reason why this doesn't work is probably because I haven't set the constraints of the ImageView and the TextView but how do I do that in code?
The ImageView should be right in the center of the ConstraintLayout while the TextView is supposed to be in the center but at the bottom.
How can I set the constraints to do what I've described above?

You are right to suspect that not setting the constraints may be the issue. To set constraints programmatically take a look at ConstraintSet.
This class allows you to define programmatically a set of constraints to be used with ConstraintLayout. It lets you create and save constraints, and apply them to an existing ConstraintLayout.
As an added bonus, ConstraintSet permits the setting of margins while setting constraints.
There are some good tutorials online about how to use ConstraintSet.

Not 100% sure here, but i have a suggestion and believe you have to call
iView .updateMargins<ConstraintLayout.LayoutParama>{//do some stuff here}.
You probably ask "Why?".
Well, i think its because you already created val clayout = ConstraintLayout(context) but didnt specify which attributesSet it has, thus taking the default one. And since your View already has defaultParams, they need to be updated now.
But please do some independet reasearch or ask a real expert with real knowledge. Because i am not really sure and this is just some suggestion.

Related

ConstrainLayout ConstraintSet - not working properly with Start/End constrains

Looks like ConstraintSet is finding hard to cope up with Start/End constrains.
This example is taken from Google samples.
Github: android-ConstraintLayoutExamples
When you replace Left & Right constrains with Start & End, ConstraintSet - not working properly, It's working with Left/Right constrains only.
For example replace
layout_constraintStart_toStartOf with layout_constraintLeft_toLeftOf & replace
layout_constraintEnd_toEndOf with layout_constraintRight_toRightOf
in following files:
constraintset_example_main.xml
constraintset_example_big.xml
Behaviour:
onClick of image:
private ConstraintSet mConstraintSetNormal = new ConstraintSet();
private ConstraintSet mConstraintSetBig = new ConstraintSet();
public void toggleMode(View v) {
TransitionManager.beginDelayedTransition(mRootLayout);
mShowBigImage = !mShowBigImage;
applyConfig();
}
private void applyConfig() {
if (mShowBigImage) {
mConstraintSetBig.applyTo(mRootLayout);
} else {
mConstraintSetNormal.applyTo(mRootLayout);
}
}
By default Android studio uses start/ end constrains hence it's I want to know root cause and possible fix.
Or Is this a bug with ConstrainSet itself?
This does look like a problem with ConstraintSet, but let's see. The following analysis is based upon the sample project with the link that you supplied.
In the sample project, I have updated ConstraintLayout to the most recent version:
compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
I did this in case we are trying to track down an issue that has already been addressed. I also updated the layout constraintset_example_big and replaced all left/right constraints with start/end constraints as follows:
constraintset_example_big.xml
<android.support.constraint.ConstraintLayout
android:id="#+id/activity_constraintset_example"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:onClick="toggleMode"
android:scaleType="centerCrop"
android:src="#drawable/lake"
app:layout_constraintDimensionRatio="h,16:9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="#string/lake_tahoe_image" />
<TextView
android:id="#+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/lake_tahoe_title"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="#+id/imageView"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="#+id/imageView" />
<TextView
android:id="#+id/textView11"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="#string/lake_discription"
app:layout_constraintStart_toStartOf="#+id/textView9"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="#+id/textView9"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="16dp"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintVertical_bias="0.0" />
</android.support.constraint.ConstraintLayout>
With these changes in place, this is what we see.
This is clearly not right. It is supposed to look like this after the transition.
After some debugging, I tracked the issue down to this line in ConstraintSetExampleActivity.java:
mConstraintSetBig.load(this, R.layout.constraintset_example_big);
ConstraintSet#load() seems to be straightforward, but if we replace the code above with an explicit inflation of the layout followed by a clone of the ConstraintSet on the inflated layout as follows:
// mConstraintSetBig.load(this, R.layout.constraintset_example_big);
ConstraintLayout cl = (ConstraintLayout) getLayoutInflater().inflate(R.layout.constraintset_example_big,null);
mConstraintSetBig.clone(cl);
We see this behavior in the app which is much better.
So my takeaway is that ConstraintSet#load() has a problem with start/end constraints. The workaround is to inflate the ConstraintLayout then do a clone.
ConstraintSetExampleActivity#onCreate()
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.constraintset_example_main);
mRootLayout = (ConstraintLayout) findViewById(R.id.activity_constraintset_example);
// Note that this can also be achieved by calling
// `mConstraintSetNormal.load(this, R.layout.constraintset_example_main);`
// Since we already have an inflated ConstraintLayout in `mRootLayout`, clone() is
// faster and considered the best practice.
mConstraintSetNormal.clone(mRootLayout);
// Load the constraints from the layout where ImageView is enlarged.
// Toggle the comment status on the following three lines to fix/break.
// mConstraintSetBig.load(this, R.layout.constraintset_example_big);
ConstraintLayout cl = (ConstraintLayout) getLayoutInflater().inflate(R.layout.constraintset_example_big,null);
mConstraintSetBig.clone(cl);
if (savedInstanceState != null) {
boolean previous = savedInstanceState.getBoolean(SHOW_BIG_IMAGE);
if (previous != mShowBigImage) {
mShowBigImage = previous;
applyConfig();
}
}
}
This issue is known and will be fixed in the 1.1 beta 6 release
https://issuetracker.google.com/issues/74253269
For those who faces issues like constraint set clone not working properly, my layout was not updating to new constraints when i called clone and applyTo methods after an api call, turns out it was due to a loading dialog i showed before the change that caused the error.

Android dataBinding - How to get resource id of a View in xml

In Android Studio my data binding itself works and is set up fine. I have a boolean defined like this:
<resources>
<bool name="showAds">false</bool>
</resources>
and in a layout.xml file i would like to referenced this boolean (which works fine) but i want to assign a id based on this boolean. Let me show you what i am trying to accomplish:
I have a button that is in a relativeLayout tag and depending on this boolean i would like to reposition the button. So I have this:
<Button
android:id="#+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="64dip"
****************
android:layout_below="#{#bool/showAds ? #+id/adone : #+id/title_main}"
****************
android:layout_centerHorizontal="true"
android:textColor="#0080FF"
android:text="#string/start_btn_title" />
See what i want to to do? I want to layout the button below a layout called adone if the showAds boolean is true, otherwise place it below a layout called title_main. Whats the syntax for this as what I have here is not compiling. I get a compile error:
expression expected after the second # sign
The above is the same problem as in How to get dimensions from dimens.xml
None of the LayoutParams attributes have built-in support. As answered in the linked article, data binding of LayoutParams was thought to be too easy to abuse so it was left out of the built-in BindingAdapters. You are not abusing it, so you should add your own.
#BindingAdapter("android:layout_below")
public static void setLayoutBelow(View view, int oldTargetId, int newTargetId) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
view.getLayoutParams();
if (oldTargetId != 0) {
// remove the previous rule
layoutParams.removeRule(RelativeLayout.BELOW);
}
if (newTargetId != 0) {
// add new rule
layoutParams.addRule(RelativeLayout.BELOW, newTargetId);
}
view.setLayoutParams(layoutParams);
}
As an aside, the #+id/adone in the binding syntax will not create the id. You should create the id in the View you're binding to.

The layout rules align_parent_end property does not show as true

At a point in my app I'm cycling through the objects on screen and checking if they're the last object in that line. To do that, I'm checking the Align Parent End property (which is checked for the last widget in each line). Here's part of my activity xml:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/relativeLayout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Average Temperature:"
android:id="#+id/AverageTemperatureText"
android:layout_below="#+id/TemperaturesText"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="10dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:id="#+id/AvgTempNum"
android:layout_alignBottom="#+id/AverageTemperatureText"
android:layout_toRightOf="#+id/AverageTemperatureText"
android:layout_below="#+id/TempMiddle"
android:gravity="center|bottom"
android:editable="false"
android:text="0.0"
android:maxLength="7"
android:nextFocusForward="#+id/TotalObservedVolumer"
android:layout_alignRight="#+id/FreeWaterVolume"
android:layout_alignEnd="#+id/FreeWaterVolume"
android:layout_alignParentEnd="true" />
^^^^ Right here. It's true.
You get the idea. Then, in my code, I'm cycling through the relative layout children, then for each view on it, checking it for that particular property. If it's true, I'm supposed to do something. But with the code I have, it's always false. So what am I doing wrong? Here it is:
RelativeLayout relLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
for(int i = 0; i < relLayout.getChildCount(); i++) {
View view = relLayout.getChildAt(i);
// Assess if it's the last field in that line
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
int[] rules = params.getRules();
if (rules[RelativeLayout.ALIGN_PARENT_END] == RelativeLayout.TRUE) {
// my code
}
}
Thanks!!
Fixed, but in a curious way.
In my case, all the last fields on screen had Align Parent End flagged. So I found online this would be the way to do it:
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
int[] rules = params.getRules();
if ((rules[RelativeLayout.ALIGN_PARENT_END] == RelativeLayout.TRUE)) {
// Do something about it
}
Where RelativeLayout.ALIGN_PARENT_END stands for 21, according to http://developer.android.com/reference/android/widget/RelativeLayout.html
However, my code was returning false for that check. So I started displaying the value for the property, and it really was false. I tried this for a while, then I saw one of my edittexts returned true for it. But the activity xml showed this
android:layout_alignParentRight="true"
in addition to alignParentEnd. Which didn't make sense, since alignParentRight is supposed to be rule 11, according to the same link above.
So I devised this code to expose which rules where true, and put it in my code:
for(int x = 0; x < 22; x++) {
if (rules[x] == RelativeLayout.TRUE) Log.i("Property true:", String.valueOf(x));
}
Which gave me 11 for all fields, and 11 and 21 for the field that responded TRUE before. Remember, all fields had android:layout_alignParentEnd="true" in the activity xml.
So to fix my code, I'm now checking rules[RelativeLayout.ALIGN_PARENT_RIGHT] and it works, but I strongly believe those two properties are switched somehow. Can anybody confirm? Or please englighten me on where I screwed up, which is more likely :)

Change value in layout.xml conditionally in Android

I'm trying to get android:layout_marginEnd="-6dp" to change to 2dp conditionally in:
<FrameLayout
android:id="#+id/wifi_combo"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginEnd="-6dp"
>
My condition is:
if (mSignalClusterStyle == STYLE_ALWAYS) {
mMobileType.setVisibility(View.VISIBLE);
} else if (mWifiVisible) {
mMobileType.setVisibility(View.GONE);
}
I would like to add a line to the if statement that overrides the -6dp with 2dp in the xml file.
I have explored setMarginEnd(), but there are very few resources on this, seeing as it is only a year old, and I keep getting a compile error with it.
What is the best way to change android:layout_marginEnd on a condition programmatically?
FrameLayout layout = (FrameLayout) findViewById(R.id.wifi_combo);
FrameLayout.LayoutParams params = (LayoutParams) layout.getLayoutParams();
params.setMarginEnd(2);
The correct way to set the endMargin is using setMarginEnd() only, added in API 17.
http://developer.android.com/reference/android/view/ViewGroup.MarginLayoutParams.html#setMarginEnd(int)
BTW, what compile errors you are getting?

android: LayoutParams for TextView makes the view disappear, programmatically

I've hit this from various different angles. Basically the gist is this:
I've layed out a template in XML for an interface which NEEDS to be run programmatically, so it's going to be populated dynamically during the run.
The problem here, is that the XML TextView has quite a few layout tweaks (which work) and are necessary. But if I actually set them in code, the TextView doesn't even show up.
(The TextView, by the way, is nested inside a TableRow, thus the call to weight.)
The XML template I designed first, to use as reference for the code is this, and it works just fine:
<TextView
android:id="#+id/txtviewWhiteBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:background="#drawable/textview_9patch_white"
android:gravity="center"
android:text="75"
android:textColor="#android:color/black"
android:layout_margin="20dp"
android:padding="20dp"
android:textSize="40dp" />
Like I said, that lays out perfectly.
When I run the same layout in code though, and apply LayoutParams, the TextView disappears.
Here's the relevant snippet:
int textViewExampleID = 9001;
private TextView txtviewExample = new TextView(this);
private void buildTextView(){
LayoutParams paramsExample = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,1.0f);
txtviewExample.setId(textViewExampleID);
txtviewExample.setBackgroundResource(R.drawable.textview_9patch_white);
txtviewExample.setGravity(Gravity.CENTER);
txtviewExample.setTextColor(getResources().getColor(android.R.color.black));
paramsExample.setMargins(20, 20, 20, 20);
txtviewExample.setPadding(20, 20, 20, 20);
txtviewExample.setTextSize(40);
txtviewExample.setText("customExample");
//if I comment out the following line, this TextView displays.
//if I leave it in, it doesn't display.
txtviewExample.setLayoutParams(paramsExample);
}
I realize there's all sorts of available classes for LayoutParams, and I've been playing with them all
LinearLayout.LayoutParams, TableView.LayoutParams, RelativeLayout.LayoutParams, LayoutParams just by itself...
No matter which one I try, any attempt at calling "setLayoutParams" renders the entire TextView gone.
I've scoured the forums here, and haven't quite found the answer. This can't be THAT uncommon.
well, that was painful but I finally got it figured out.
The most important thing to remember (that I just realized) is that of all the myriads of LayoutParams, you need to use the one that relates to the PARENT of the view you're working on, not the actual view.
So in my case, I was trying to get the TextView margins working, but it was being put inside a TableRow. The one simple change was ensuring that the type of LayoutParams being used were the ones for TableRow:
private void buildTextView(){
// the following change is what fixed it
TableRow.LayoutParams paramsExample = new TableRow.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,1.0f);
txtviewExample.setId(textViewExampleID);
txtviewExample.setBackgroundResource(R.drawable.textview_9patch_white);
txtviewExample.setGravity(Gravity.CENTER);
txtviewExample.setTextColor(getResources().getColor(android.R.color.black));
paramsExample.setMargins(20, 20, 20, 20);
txtviewExample.setPadding(20, 20, 20, 20);
txtviewExample.setTextSize(40);
txtviewExample.setText("customExample");
txtviewExample.setLayoutParams(paramsExample);
}
Thanks guys, hopefully this will come in handy for somebody else down the line, as I saw a lot of semi-related questions in the forums here, but not one that really defines the problem.
private TextView txtviewExample = new TextView(this);
private void buildTextView(){
LayoutParams paramsExample = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,1.0f);
txtviewExample.setId(textViewExampleID);
txtviewExample.setBackgroundResource(R.drawable.textview_9patch_white);
txtviewExample.setGravity(Gravity.CENTER);
txtviewExample.setTextColor(getResources().getColor(android.R.color.black));
paramsExample.setMargins(20, 20, 20, 20);
txtviewExample.setPadding(20, 20, 20, 20);
txtviewExample.setTextSize(40);
txtviewExample.setText("customExample");
setContentView(txtviewExample);//when you don't use SETTER method for TextView you can't view the desireable text on the UI//
}
//use
what is the 3rd variable in layoutparams supposed to do, is that alpha? what happens if you comment out paramsExample.setMargins
finally what happens if you to txtviewExample.setVisible(View.Visible) after you setLayoutParams?
those would be the things I would try if you haven't

Categories

Resources