Handling GONE views puzzle in ConstraintLayout - android-layout

I have a simple enough looking layout with what turns out to be quite a tricky behaviour to accomplish using xml alone i.e. using only the features of ConstraintLayout and not having to do anything programmatically.
I have considered Barriers & Guidlines and many scenarios and trials with no success; so this is my last hope that maybe someone else knows something I don't.
Here is my puzzle:
If 3 lines visible -> image should be centred between line 1 and line
2
If 2 lines visible -> image should be centred between line 1 and
line 2
If 1 line visible (label_text) -> image should be centred in parent, or
centre aligned with line 1 (label_text)
Here are some images to illustrate:
3 Lines - correct
2 Lines - correct
1 Line incorrect but best I can get so far [when only Label is visible]
1 Line correct the way I want it to be [when only Label is visible]
Code:
<androidx.constraintlayout.widget.ConstraintLayout
style="#style/V2.ItemList.Background"
android:minHeight="#dimen/item_minimum_height"
android:paddingVertical="#dimen/=margin_vertical">
<ImageView
android:id="#+id/icon"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
tools:src="#drawable/ic_img"
tools:visibility="visible" />
<TextView
android:id="#+id/label_text"
app:layout_constraintBottom_toTopOf="#id/line1_text"
app:layout_constraintEnd_toStartOf="#id/right_content"
app:layout_constraintStart_toEndOf="#id/icon_start"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Label" />
<TextView
android:id="#+id/line1_text"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="#id/line2_text"
app:layout_constraintEnd_toStartOf="#id/right_content"
app:layout_constraintStart_toEndOf="#id/icon"
app:layout_constraintTop_toBottomOf="#id/label_text"
tools:text="Line 1"
tools:visibility="gone" />
<TextView
android:id="#+id/line2_text"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/right_content"
app:layout_constraintStart_toEndOf="#id/icon"
app:layout_constraintTop_toBottomOf="#id/line1_text"
tools:text="Line 2"
tools:visibility="gone" />
</androidx.constraintlayout.widget.ConstraintLayout>
Any help is much appreciated!
UPDATE
See Cheticamp's answer below which is best solution but in case it's useful for anyone else here's the way I was going to do it programmatically if I couldn't find an xml only solution:
private fun adjustConstraints() {
if(binding.line1Text.isGone && binding.line1Text.isGone) {
ConstraintSet().apply {
clone(binding.itemListLayout)
// Adjust left/start content for single line
connect(
R.id.icon,
ConstraintSet.TOP,
R.id.item_list_layout,
ConstraintSet.TOP
)
connect(
R.id.icon,
ConstraintSet.BOTTOM,
R.id.item_list_layout,
ConstraintSet.BOTTOM
)
// Adjust right/end content for single line
connect(
R.id.right_content,
ConstraintSet.TOP,
R.id.item_list_layout,
ConstraintSet.TOP
)
connect(
R.id.right_content,
ConstraintSet.BOTTOM,
R.id.item_list_layout,
ConstraintSet.BOTTOM
)
}.also {
it.applyTo(binding.itemListLayout)
}
}
}

Constrain the ImageView to the top of label_text and to the bottom of line_1_text.
<ImageView
android:id="#+id/icon"
app:layout_constraintTop_toTopOf="#id/label_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="#id/line1_text"
tools:src="#drawable/ic_img"
tools:visibility="visible" />

Related

Why doesn't textView21.SetLeftTopRightBottom(1,200,45, 275) change the size of a textview?

Why doesn't textView21.SetLeftTopRightBottom(1,200,45, 275) change the size of a textview?
<TextView
android:id="#+id/textView21_id"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:layout_x="22dp"
android:layout_y="105dp"
android:height="50dp"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:textSize="30sp"
android:textColor="#000000"
android:background="#9999cc"
android:singleLine="false"/>
There's the activity_main.xml snippet. Is there something there which overrides the SetLeftTopRightBottom?
I am still trying to get two different but ordinary mobile phones (cell phones) to display a view the same.
pic of same app in two phones
You can see the left hand pic shows to below the grey '6:' textview and includes the 'Go' textview and all the right hand 5th-letter-in-the-word textview areas whereas the other pic doesn't.
I've figured out how to get each phone's display metrics
var metrics = Resources.DisplayMetrics;
gnumWidthDp = ConvertPixelsToDp(metrics.WidthPixels);
gnumHeightDp = ConvertPixelsToDp(metrics.HeightPixels);
I thought it would be easy to do the SetLeftTopRightBottom thing and set each textview in the right place.
Please can you tell me what I have missed? Thank you all.
In the official document, SetLeftTopRightBottom method is meant to be used in animations only as it applies this position and size for the view only temporary and it can be changed back at any time by the layout.
More information: https://developer.android.com/reference/android/view/View#setLeftTopRightBottom(int,%20int,%20int,%20int)
In addition, the size of the textview21 had been ensured in the xml. If you want to set the size of it dynamically, you need to use the LayoutParams. Such as:
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(300, 200);
//300 is width and 200 is height
textView.LayoutParameters = layoutParams;

Inside hollow shape rectangle drawable / canvas shape

I'm trying to create a drawable shape with stroke for my popup layout background.
and
I tried to play around with radius but didn't get the desired result.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:color="?colorSecondary" android:width="1dp"/>
<solid android:color="?colorSurface"/>
<corners
android:topLeftRadius="#dimen/card_corner_radius"
android:topRightRadius="#dimen/card_corner_radius"
android:bottomLeftRadius="#dimen/card_corner_radius"
android:bottomRightRadius="#dimen/card_corner_radius" />
</shape>
I tried with the canvas but cannot achieve second picture
Why can't you simply use the graphics that you posted as a PNG file? Other options follow.
You could decompose your drawing to its components and build a LayerList drawable from the components. For instance, your first image looks like is is composed of two horizontal lines and arcs of ovals at either end. Four drawables, each representing one of these figures and stacked would produce your first image. It would be similar for the second image.
Since you already have the image you want, you could paste it into a vector graphic editing program such as InkScape, export the SVG file and import the SVG file into Android Studio (File->New->Vector Asset and select local SVG file). I did this with your second image and came up with the following:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="145.83989dp"
android:height="26.347599dp"
android:viewportWidth="516.7555"
android:viewportHeight="93.357635">
<path
android:pathData="m10,93.107c-8.631,-0.552 -9.5,-0.79 -9.5,-2.607 0,-1.877 0.86,-2.036 14.026,-2.58 15.353,-0.635 17.206,-1.257 21.838,-7.331 6.399,-8.389 7.237,-21.039 2.028,-30.609 -3.638,-6.685 -6.619,-8.98 -11.661,-8.98 -2.2,0 -5.739,-0.521 -7.865,-1.158 -3.309,-0.991 -3.866,-1.567 -3.866,-4 0,-1.859 -0.519,-2.842 -1.5,-2.842 -0.825,0 -1.5,-0.675 -1.5,-1.5 0,-1.876 1.394,-1.935 2.899,-0.122 0.629,0.758 3.497,1.62 6.372,1.917 2.876,0.296 6.235,0.852 7.466,1.235 1.739,0.541 3.006,-0.072 5.691,-2.758 1.9,-1.9 3.755,-4.654 4.123,-6.12 1.726,-6.878 -2.782,-14.742 -9.625,-16.793 -2.649,-0.794 -3.926,-1.753 -3.926,-2.949 0,-1.043 -0.926,-1.951 -2.25,-2.206 -2.005,-0.386 -1.963,-0.448 0.393,-0.57 1.454,-0.075 2.902,-0.811 3.219,-1.636 0.509,-1.327 26.338,-1.5 224.138,-1.5 193.862,0 223.636,0.192 224.116,1.443 0.42,1.093 1.703,1.307 5.302,0.88 10.074,-1.193 22.04,5.074 28.511,14.931 12.842,19.565 10.573,48.147 -5.032,63.388 -2.896,2.828 -7.279,5.911 -9.741,6.851 -2.766,1.056 -4.677,2.481 -5.004,3.73l-0.528,2.02 -229.812,-0.372c-126.396,-0.204 -231.837,-0.098 -234.312,0.235 -2.475,0.334 -8.775,0.334 -14,0zM470,87c-1.098,-0.71 -0.362,-0.973 2.75,-0.985 2.338,-0.008 4.253,-0.353 4.255,-0.765 0,-0.412 2.816,-0.778 6.25,-0.813 7.354,-0.075 11.176,-1.816 17.191,-7.83 13.89,-13.89 15.272,-41.457 2.892,-57.69 -7.683,-10.075 -19.195,-14.271 -28.588,-10.42 -1.202,0.493 -1.75,0.254 -1.75,-0.765 0,-0.86 -1.312,-1.744 -3.125,-2.107 -1.719,-0.344 -100.528,-0.625 -219.577,-0.625L33.847,5l3.219,2.709c8.558,7.201 9.075,19.05 1.198,27.474l-2.508,2.682 3.532,4.318c4.135,5.055 7.713,14.889 7.713,21.197 0,5.993 -3.103,15.578 -6.473,19.997l-2.757,3.615 109.365,0.259c300.91,0.712 324.326,0.694 322.865,-0.25zM453.667,70.333c-0.367,-0.367 -0.667,-1.132 -0.667,-1.7 0,-0.627 0.466,-0.568 1.183,0.15 0.651,0.651 0.951,1.416 0.667,1.7 -0.284,0.284 -0.817,0.217 -1.183,-0.15zM0,80.5c0,-0.825 0.177,-1.5 0.393,-1.5 0.216,0 0.652,0.675 0.969,1.5 0.317,0.825 0.14,1.5 -0.393,1.5 -0.533,0 -0.969,-0.675 -0.969,-1.5z"
android:fillColor="#000000"/>
</vector>
Which looks like this when displayed in an ImageView:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_blue_light"
tools:context=".MainActivity">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:adjustViewBounds="true"
android:src="#drawable/ic_image"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
The image can be scaled and accurately reflect the original image at any size screen. You can use any graphics editor that can produce an SVG file.

What is equivalent of "toStartOf" and "toTopOf" in ConstraintSet?

How is it possible to set correctly layout_constraintStart_toStartOf and layout_constraintTop_toTopOf programmaticly?
<ImageView
android:id="#+id/firstButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/alarm"
app:layout_constraintStart_toStartOf="#+id/guideline4"
app:layout_constraintTop_toTopOf="#+id/guideline" />
So far, I can't find toStartOf and toTopOf properties of ConstraintSet, what is the equivalent of it?
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(main_layout);
constraintSet.connect(R.id.firstButton, ConstraintSet.START, R.id.guideline4, ConstraintSet.END);
constraintSet.connect(R.id.firstButton, ConstraintSet.TOP, R.id.guideline, ConstraintSet.BOTTOM);
constraintSet.applyTo(main_layout);
I guess that if you want start to start and top to top, it is more like
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(main_layout);
constraintSet
.connect(R.id.firstButton, ConstraintSet.START, R.id.guideline4, ConstraintSet.START);
constraintSet
.connect(R.id.firstButton, ConstraintSet.TOP, R.id.guideline, ConstraintSet.TOP);
constraintSet.applyTo(main_layout);
?

how do I change the android:layout_marginTop of a button?

I need to change the property android:layout_marginTop of a button programmatically. But the code below does not produce the same result as changing on the xml. I wonder if anyone can spot the issue, here's my button:
<Button
android:id="#+id/cta_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="0dp"
android:background="#color/cta_button_background"
android:text="CTA"
android:textColor="#color/cta_button_foreground"
android:textSize="18sp"
android:visibility="visible" />
now I need to change the "marginTop" programmatically based on some logic. Here is what I have tired but does not work properly.
// Adjust button to float above the image
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
int marginTop = Pixel.convertPxToDp(someNumber);
params.setMargins(0, marginTop, 0, 0);
mCallToActionButton.setLayoutParams(params);
mCallToActionButton.invalidate();
"mCallToActionButton" has a valid pointer to the button and 'someNumber' can be anything value.
I used this thread but the button is moving somewhere else, not just changing its topMargin
How to set a button's parameters programatically
thank you.
This way works:
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mCallToActionButton.getLayoutParams();
params.topMargin = Pixel.convertDpToPx(newImageMargin);
mCallToActionButton.setLayoutParams(params);
Try to set gravity to your LayoutParams
params.gravity = Gravity.CENTER_HORIZONTAL;

RelativeLayout with ImageView - calculate position of elements

I have a problem with my android code. I have the following code
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:orientation="vertical">
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:layout_centerVertical="true"
android:src="#drawable/pdf" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/imageView1"
android:layout_alignLeft="#+id/imageView1"
android:text="Test-Label"
android:textColor="#color/red" />
</RelativeLayout>
I want to position the textview now in my imageview and use the following code
ImageView iv = (ImageView) findViewById(R.id.imageView1);
int width = iv.getWidth();
int height = iv.getHeight();
float percentMarginTop = 58f;
float percentMarginLeft = 65f;
float percentTextSize = 3f;
float marginTop = height / 100f * percentMarginTop;
float marginLeft = width / 100f * percentMarginLeft;
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, Math.round(height / 100f * percentTextSize));
RelativeLayout.LayoutParams lpTv = (RelativeLayout.LayoutParams) tv.getLayoutParams();
lpTv.topMargin = Math.round(marginTop);
lpTv.leftMargin = Math.round(marginLeft);
So I want to position the elements with the percentage values calculated of the actual width and height of the imageview. So in my opinion the elements should position correct on each device not carrying about the density (ldpi, mdpi, xhdpi, ...) and screen size (small, normal, large, xlarge, ...) but the position on a handy (4") is correct but not correct on another device like a tablet (10"). How could that be when I'm working with percentages on the given ImageView?
Looks like it was a dumb beginner mistake I didn't want to see or wanted to ignore it ;)
width / 100 returns not the float value, but the int value. And then the whole calculation fails due to a false value which gets multiplicated.
I changed my code which is now a working snippet

Resources