Getting measured height in Android Studio doesn't work properly - android

I have multiple list views inside a scrollable view, so I used a function that computes the height of a list view and sets it so the list view is not scrollable anymore.
public static void setHeightListView(ListView listView) {
Adapter adapter = listView.getAdapter();
int UNBOUNDED = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int height = listView.getDividerHeight() * (listView.getCount() - 1);
for (int i = 0; i < adapter.getCount(); ++i) {
View child = adapter.getView(i, null, listView);
child.measure(UNBOUNDED, UNBOUNDED);
height += child.getMeasuredHeight();
}
ViewGroup.LayoutParams listViewParams = listView.getLayoutParams();
listViewParams.height = height;
listView.requestLayout();
}
This function has worked fine so far, but it doesn't compute the correct height for this in getView() in my adapter:
convertView = inflater.inflate(R.layout.activity_frame_no_rounded_corners, null);
activity_frame_no_rounded_corners.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="10dp"
android:focusable="false"
android:background="#drawable/textview_white">
<LinearLayout
android:layout_width="match_parent"
android:focusable="false"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageview_modify"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:focusable="false"
android:gravity="center_vertical"
android:src="#drawable/ic_baseline_remove_circle_24" />
<LinearLayout
android:layout_width="match_parent"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:focusable="false"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textview_key"
android:text="Key"
android:textSize="15dp"
android:padding="7dp"
android:textColor="#000000"
android:focusable="false"
android:layout_width="0dp"
android:layout_weight="0.4"
android:layout_height="wrap_content"
android:hint="Vlue"/>
<View
android:id="#+id/vertical_bar_devider"
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#dcdcdc"/>
<EditText
android:id="#+id/edittext_value"
android:text="Value"
android:textSize="15dp"
android:padding="7dp"
android:textColor="#000000"
android:layout_width="0dp"
android:layout_weight="0.6"
android:layout_height="wrap_content"
android:hint="Value"
android:background="#drawable/textview_white"
android:drawableRight="#drawable/ic_baseline_arrow_forward_ios_24_gray"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
If I use a different xml then it computes the right height. Also, if I remove the weight from the views it also computes the right height (but I need the weight for alignment, I couldn't find a way around it).
You can see in the Screenshot the different list views that I have (one for the names, one for the dob, one for the grade, one for the email, one for the gmc no, one for the specialities).
For testing purposes, they do not have any margins, so they should be one right after the other.
As you can see, the height of the email list view is computed correctly, but my function fails for the rest of the lists. If I change "GMC Number" to "Email" then the function computes the right height for the gmc no list view as well (idk why, it's just an observation).
I guess my problem has something to do with the weight, but I have no idea how to fix it.
Thank you in advance!

Related

Android: Same Images in table different size - ONLY when not debugging

I am trying to display a table that has three rows. The first two are images, the third is just data. I have tried to set them up with table row weights of 45%, 45%, 10%... However that never happens, it always come out somewhere about 47%, 47%, 6%.
But that's minor compared to the behavior that I can't figure out.
The images and data come in async, so they are populated using a "runnable".
The problem is the first image gets bigger every time it updates. And the second image keeps getting smaller.
However, here's the kicker, when I set breakpoints and pause it to debug it, it works exactly as I want it to. It doesn't change sizes, the row heights do not change.
So, that said, here is my layout XML:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:layout_weight="1"
android:id="#+id/mainscreen">
android:background="#00ff00"
<TableRow
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="#+id/img1box"
android:layout_weight="45"
android:gravity="center_vertical|center_horizontal">
<ImageView
android:contentDescription="image1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/img1"
android:src="#drawable/icon"/>
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="#+id/img2box"
android:layout_weight="45"
android:gravity="center_vertical|center_horizontal">
<ImageView
android:contentDescription="image2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/img2"
android:src="#drawable/icon" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:id="#+id/dataholder"
android:gravity="center_vertical|center_horizontal">
<TextView
android:id="#+id/statusbox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:textColor="#000000"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_gravity="center"/>
</TableRow>
</TableLayout>
I have tried settings such as 0dp (or 0px), fill_parent, match_parent, wrap_content, and a dozen other configurations from web searches.
And the code snippets that happen when the data/images are posted (removed the parts that do stuff like findViewById(), that happens at onCreate() and works fine, plus rename some confidential variables):
final Runnable HandleImage1Ready = new Runnable() {
#Override
public void run() {
int height, width;
float xfactor, yfactor;
height = m_Image1Box.getHeight(); // This is the TableRow
width = m_Image1Box.getWidth();
// Compute the reduction factor, but it's
// always by height right now, so we just use that
Bitmap image = BitmapFactory.decodeByteArray(m_img1, 0, m_img1.length);
yfactor = height / (float) image.getHeight();
xfactor = width / (float) image.getWidth();
// create a new bitmap, I even try reducing the "height"
// to prevent the table row from growing... doesn't help
Bitmap scaled = Bitmap.createScaledBitmap(image, (int) (image.getWidth() * yfactor), height, true);
m_Image1.setImageBitmap(scaled);
CompleteProcessing();
}
};
final Runnable HandleImage2Ready = new Runnable() {
#Override
public void run() {
int height, width;
float xfactor, yfactor;
height = m_Image2Box.getHeight(); // This is the TableRow
width = m_Image2Box.getWidth();
// EVEN TRY USING THE SAME IMAGE ON ROW 2...
//Bitmap image = BitmapFactory.decodeByteArray(m_img2, 0, m_img2.length);
Bitmap image = BitmapFactory.decodeByteArray(m_img1, 0, m_img1.length);
yfactor = height / (float) image.getHeight();
xfactor = width / (float) image.getWidth();
Bitmap scaled = Bitmap.createScaledBitmap(image, (int) (image.getWidth() * yfactor), height, true);
m_Image2.setImageBitmap(scaled);
CompleteProcessing();
}
};
final Runnable HandleMicrReady = new Runnable() {
#Override
public void run() {
int height, width;
// Just to debug these, and see how this row changes
height = m_statusBox.getHeight();
width = m_statusBox.getWidth();
m_statusBox.setText(m_data);
CompleteProcessing();
}
};
Repeating... When I set a break point in one of the above functions, and resume the execution, both images are the same size, every time it posts new images. Which is what I want to happen.
But if I don't set the break point, every time a new image is posted, the top table row gets bigger and bigger. To the point that the top image is over 50% of the table (screen), and the bottom image and table row of data are getting smaller.
In essence, I believe Android Studio is laughing at me because, like a rattle in a car you take in, it doesn't do it when someone is watching for the problem...
(I included an "android-studio" tag, because pausing it in AS debugger causes the problem it disappear).
Any advice is appreciated.
-Scotty
Table layouts do not seem to take the weights placed upon them very strictly. E.g. when you add an ImageView to a TableRow with or without a src it already renders slightly differently. I also verified this with 2 images with different dimensions and the row with the bigger image completely overtakes the row of the smaller one.
The solution is to not use a TableLayout. If you don't want to use something like a GridView I suggest sticking with LinearLayout. You can use it in the exact same manner. You only need to specify its android:orientation="horizontal|vertical" attribute instead of making a distinction between TableRow (the horizontal kind) or TableLayout (the vertical kind)
Here's a visual comparison:
So for your provided layout XML this would become:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:weightSum="100"
android:background="#00ff00"
android:id="#+id/mainscreen">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="#+id/img1box"
android:layout_weight="45"
android:gravity="center_vertical|center_horizontal">
<ImageView
android:contentDescription="image1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/img1"
android:src="#drawable/icon"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="#+id/img2box"
android:layout_weight="45"
android:gravity="center_vertical|center_horizontal">
<ImageView
android:contentDescription="image2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/img2"
android:src="#drawable/icon" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:id="#+id/dataholder"
android:gravity="center_vertical|center_horizontal">
<TextView
android:id="#+id/statusbox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:textColor="#000000"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_gravity="center"/>
</LinearLayout>
</LinearLayout>

Set Fragment height programmatically according to existing elements

Pre:
I am extending the relativelayout class and inflating the below reduced xml sample
I am adding the fragment programmatically in the container layout "fragment_container"
What I want to achieve is to add a fragment in a layout-container (in this case fragment_container) where the height is already ruled by the three textviews
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:layout_marginTop="10dp"
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text 1" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView"
android:text="New Text 2" />
<TextView
android:layout_marginBottom="10dp"
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView2"
android:text="New Text 3" />
</RelativeLayout>
To set the height of the fragment programmatically I am doing this:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus) return;
ViewGroup.LayoutParams params = fragment.getView().getLayoutParams();
params.height = getMeasuredHeight();
params.width = getMeasuredWidth();
fragment.getView().setLayoutParams(params);
}
This solution works sometimes (sometimes getMeasuredHeight returns 0 && getMeasuredWidth returns 0), so it's not the correct solution.
Is this a problem that can be solved through the use of the xml only?
As I see you are stacking the views vertically, isn't it better to use LinearLayout with a vertical orientation, and give each view a proper weight (0 for height, and proper value for weight)?

Android: Listview inside ScrollView

I want to have a layout that can scroll and a listview inside it.
The listview will expand it's height base on how many items in it. Only the ScrollView outside is scrollable.
This is my code:
<ScrollView
android:id="#+id/layout_box"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="#dimen/layout_height_small"
android:gravity="center_vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginLeft="#dimen/layout_margin_medium"
android:layout_marginTop="#dimen/layout_margin_medium"
android:gravity="center"
android:text="#string/list_regist_box_content"
android:textSize="#dimen/text_size_medium"
android:textStyle="bold" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ffffff" >
<ListView
android:id="#+id/list_registed_box"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="#+id/btn_add_regist_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="3dp"
android:gravity="center"
android:paddingBottom="#dimen/layout_margin_medium"
android:paddingTop="#dimen/layout_margin_medium"
android:text="#string/add_regist_box"
android:textColor="#0F88FF"
android:textSize="#dimen/text_size_medium" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginLeft="#dimen/layout_margin_medium"
android:layout_marginTop="#dimen/layout_margin_large"
android:gravity="center"
android:text="#string/amount"
android:textSize="#dimen/text_size_medium"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="#dimen/common_row_height"
android:background="#drawable/white_bg_grey_border_bottom"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="#+id/list_regist_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="#dimen/layout_margin_medium"
android:layout_marginRight="#dimen/layout_width_medium"
android:gravity="center_vertical"
android:text="#string/total"
android:textSize="#dimen/text_size_medium" />
</LinearLayout>
</ScrollView>
But the listview is neither expanded nor scrollable.
Please help!
Don't put ListView inside ScrollView - first rule of android clud :)
Instead you can use simple LinearLayout and manage you ListView items inside it.
Or you can add Header/Footer Views to the ListView and using it without scrollview.
Actually, it is possible to put a ListView inside of an ScrollView. In some use cases (e.g. dynamic menus/submenus it's a reasonable solution). However, two caveats apply:
The ListView won't have scroll. In general, nested scrolling is not possible in Android. There are some hacks to make it work (mostly by using requestDisallowInterceptTouchEvent()) but it's hard to make them work correctly in all cases.
As a consequence, you must indicate the exact height the ListView needs to show all items (via its appropriate LayoutParams). Setting WRAP_CONTENT will not work.
I used below lines of code to scroll list item inside scroll view. It's working fine for my requirement, i hope it will help you.
Thanks,
Murali.M
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
//pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}

Android View.getDrawingCache scale bitmap incorrect

I am creating a list view for message of different heights. The views are xml layout which are setup to layout the same on all resolution screens. To increase performance I am converting these view into a bitmap image by calling View.getDrawingCache(). I am getting the Bitmap image but it seems to be scaling the text, especially in the high resolution screens. This is leaving the text a little blurry and in some case it is also being cut off at the edges. If I layout the View rather than the bitmap image, everything is scaled correctly but I am not getting the performance i desire. My item xml layout looks like this:
Xml Item View:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5px"
android:background="#FFFFFF">
<ImageView android:id="#+id/contact_photo"
android:layout_width="48dip"
android:layout_height="48dip"/>
<ImageView android:id="#+id/network_icon"
android:layout_alignParentRight="true"
android:layout_width="16dip"
android:layout_height="16dip"/>
<TextView android:id="#+id/created_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_toLeftOf="#+id/network_icon"
android:textColor="#000000"/>
<TextView android:id="#+id/sender_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_toRightOf="#+id/contact_photo"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#000000"/>
<TextView android:id="#+id/summary"
android:layout_below="#+id/sender_name"
android:layout_toRightOf="#+id/contact_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:maxLines="4"
android:textColor="#000000" />
<LinearLayout
android:id="#+id/AttachmentLayout"
android:layout_below="#+id/summary"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_width="wrap_content"/>
</RelativeLayout>
View Measure Snippet:
LayoutParams params = child.getLayoutParams();
if (params == null) {
params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
final int index = layoutMode == LAYOUT_MODE_ABOVE ? 0 : -1;
child.setDrawingCacheEnabled(true);
addViewInLayout(child, index, params, true);
final int itemWidth = (int)(getWidth() * ITEM_WIDTH);
child.measure(MeasureSpec.EXACTLY | itemWidth, MeasureSpec.UNSPECIFIED);
I have also added the snippet of code preforming the measurement of the view. Does anyone know how to prevent the text from scaling?
Ok... folks I figure it out. It was really simple and should have know this from the beginning. The solution is to make sure you add the to the AndroidManifest.xml. I set the supported resolution to any because my xml layout files are designed to automation re-size.

Two TextViews side by side, only one to ellipsize?

I want to have two TextView elements appear side by side (in a list item), one aligned to the left, one to the right. Something like:
|<TextView> <TextView>|
(the | represent the screen's extremities)
However, the TextView on the left can have content that is too long to fit on the screen. In this case, I want to have it ellipsize but still show the entire right TextView. Something like:
|This is a lot of conte...<TextView>|
I have had numerous attempts at this, using both LinearLayout and RelativeLayout, and the only solution I have come up with is to use a RelativeLayout and put a marginRight on the left TextView big enough to clear the right TextView. As you can imagine, though, this is not optimal.
Are there any other solutions?
Final, LinearLayout solution:
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:inputType="text"
/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="0"
android:layout_gravity="right"
android:inputType="text"
/>
</LinearLayout>
Old, TableLayout solution:
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"
android:shrinkColumns="0"
>
<TableRow>
<TextView android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
/>
<TextView android:id="#+id/date"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="none"
android:gravity="right"
/>
</TableRow>
</TableLayout>
Just an idea, why don't you declare first in the xml layout the textview on the right and set its width as wrap content, android:layout_alignParentRight="true" and android:gravity="right". Then declare the textview on the left, set its width as fill parent, android:layout__toLeftOf={the id of the textview on the right} having RelativeView as the root view.
By declaring first the right textview, its required width will be computed first and occupy the view while the textview on the left will occupy the remaining space of the view.
I still have not tried this though it might give you some idea.
[Update]
I tried creating an xml resource layout... and it somehow works...
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/right"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text="right"
>
</TextView>
<TextView
android:id="#+id/left"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#id/right"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:singleLine="true"
android:maxLines="1"
android:text="too looooooooooong ofskgjo sdogj sdkogjdfgds dskjgdsko jgleft"
>
</TextView>
</RelativeLayout>
The LinearLayout answer worked for me with this same problem. Posted as a separate answer because it wasn't clear what did and didn't work for the asker.
One difference. TableLayout was less ideal for me because I had two rows of data, and I wanted the bottom row to behave as this question describes, and the top row to span the area. That question's been answered in another SO question: Colspan in TableLayout, but LinearLayout was simpler.
Though getting the widths right took me a bit. I included the android lint tweak of using 0dp width on the scaling item for performance.
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
>
<TextView
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:ellipsize="end"
android:inputType="text"
/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="0"
android:layout_gravity="right"
android:inputType="text"
/>
</LinearLayout>
Use TableLayout and put both TextView in table row, have a try. I haven't tried
There are many answers to this and practically equivalent, duplicate questions on SO. The suggested approaches usually work, sort of. Putting it into a LinearLayout, wrap the whole in an extra RelativeLayout, use a TableLayout; all these seem to solve it for a simpler layout but if you need these two TextViews inside something more complicated, or the same layout will be reused, for instance, by a RecyclerView, things get broken very quickly.
The only solution I found that really works all the time, regardless of what bigger layout you put it into, is a custom layout. It's very simple to implement, and being as lean as it possibly gets, it will keep the layout reasonably flat, it's easy to maintain—so in the long run, I consider this the best solution to the problem.
public class TwoTextLayout extends ViewGroup {
public TwoTextLayout(Context context) {
super(context);
}
public TwoTextLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TwoTextLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
if (count != 2)
throw new IllegalStateException("TwoTextLayout needs exactly two children");
int childLeft = this.getPaddingLeft();
int childTop = this.getPaddingTop();
int childRight = this.getMeasuredWidth() - this.getPaddingRight();
int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
int childWidth = childRight - childLeft;
int childHeight = childBottom - childTop;
View text1View = getChildAt(0);
text1View.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
int text1Width = text1View.getMeasuredWidth();
int text1Height = text1View.getMeasuredHeight();
View text2View = getChildAt(1);
text2View.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
int text2Width = text2View.getMeasuredWidth();
int text2Height = text2View.getMeasuredHeight();
if (text1Width + text2Width > childRight)
text1Width = childRight - text2Width;
text1View.layout(childLeft, childTop, childLeft + text1Width, childTop + text1Height);
text2View.layout(childLeft + text1Width, childTop, childLeft + text1Width + text2Width, childTop + text2Height);
}
}
The implementation couldn't be simpler, it just measures the two texts (or any other child views, actually) and if their combined width exceeds the layout width, reduces the width of the first view.
And if you need modifications, eg. to align the second text to the baseline of the first, you can solve that easily, too:
text2View.layout(childLeft + text1Width, childTop + text1Height - text2Height, childLeft + text1Width + text2Width, childTop + text1Height);
Or any other solution, like shrinking the second view in relation to the first, aligning to the right, etc.
Why don't you put a left margin on the right TextView? I'm using this approach for a
|<TextView> <ImageButton>|
and it works.
Solution with ConstraintLayout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="#+id/leftText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintEnd_toStartOf="#id/rightText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="This is a lot of content that should be cut" />
<TextView
android:id="#+id/rightText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Right text" />
</androidx.constraintlayout.widget.ConstraintLayout>
When I faced with the sililar issue, I did following:
I needed:
|<TextView, may be long> <TextViewFixedSize> |
|<TextView, may be longer ...> <TextViewFixedSize>|
|<TextViewLong> <TextViewFixedSize> |
You may use a solution like this:
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layoutRecommendedServiceDescription"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/textViewRecommendedServiceTitle"
app:layout_constraintTop_toBottomOf="#id/textViewRecommendedServiceTitle">
<TextView
android:id="#+id/textViewRecommendedService1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintEnd_toStartOf="#+id/textViewRecommendedServicePopular"
app:layout_constraintStart_toStartOf="parent"
tools:text="Long text"
tools:visibility="visible" />
<TextView
android:id="#+id/textViewRecommendedServicePopular"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:lines="1"
android:text="#string/services_popular"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/textViewRecommendedService1"
app:layout_goneMarginStart="0dp"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

Categories

Resources