GridLayout. How set space between columns? - android

Android Studio 3.1, Java 1.8, Gradle 4.1
I use GridLayout.
All work fine.
But I need to set space (e.g. 10dp) between columns and space between rows.
How I can do this?
main.xml:
<GridLayout
android:id="#+id/categoriesContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:verticalSpacing="10dp"
app:layout_constraintEnd_toEndOf="#+id/birthDateContainer"
app:layout_constraintStart_toStartOf="#+id/birthDateContainer"
app:layout_constraintTop_toBottomOf="#+id/birthDateContainer">
</GridLayout>
profile_category_active.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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.support.constraint.ConstraintLayout
android:id="#+id/profileCategoryContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/categoryNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginEnd="30dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="30dp"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:maxLines="1"
android:text="TextView" />
</android.support.constraint.ConstraintLayout>
</layout>
Activity: I add row programatically:
GridLayout gridLayout = findViewById(R.id.categoriesContainer);
gridLayout.setColumnCount(columnCount);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int index = 0; index < 10; index++) {
View profileCategoryActive = inflater.inflate(R.layout.profile_category_active, null, false);
categoriesGridContainer.addView(profileCategoryActive);
ConstraintLayout profileCategoryContainer = profileCategoryActive.findViewById(R.id.profileCategoryContainer);
ViewGroup.LayoutParams profileCategoryContaineParams = profileCategoryContainer.getLayoutParams();
profileCategoryContaineParams.width = (int) AndroidUtil.dpToPx(this, categoryItemWidth);
profileCategoryContainer.setLayoutParams(profileCategoryContaineParams);
TextView categoryNameTextView = profileCategoryActive.findViewById(R.id.categoryNameTextView);
categoryNameTextView.setText("Ind " + profileCategoryContaineParams.width);
}

In xml GridLayout, add:
android:useDefaultMargins="true"
and you get a distance between columns and rows.

This is how I achieved it, hopefully this helps somebody;
<GridLayout
android:orientation="horizontal"
android:columnCount="3"
android:layout_marginEnd="-10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:background="#color/colorBlack"
android:textColor="#color/colorWhite"
android:text="1"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:layout_columnWeight="1"
android:layout_height="wrap_content"
android:padding="15dp" />
<TextView
android:background="#color/colorBlack"
android:textColor="#color/colorWhite"
android:text="2"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:layout_columnWeight="1"
android:layout_height="wrap_content"
android:padding="15dp" />
<TextView
android:background="#color/colorBlack"
android:textColor="#color/colorWhite"
android:text="3"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:layout_columnWeight="1"
android:layout_height="wrap_content"
android:padding="15dp" />
<TextView
android:background="#color/colorBlack"
android:textColor="#color/colorWhite"
android:text="4"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:layout_columnWeight="1"
android:layout_height="wrap_content"
android:padding="15dp" />
</GridLayout>
Essentially what it's doing is setting a margin on each item (10dp) to space them inside the GridLayout and then it's shifting the GridLayout by using a negative margin (-10dp) to compensate for the additional width. Giving the following result;

Dynamic Views in GridLayout
I had a slightly different problem. The Views I needed to show in the GridLayout could not be determined ahead of time (i.e. can't create them in XML). I needed to create them programmatically based on info loaded from a database.
for (socialPlatform in platformsWithNoAccount) {
val socialIcon = ImageView(requireContext())
socialIcon.setImageDrawable(ImageUtils.getSocialIcon(socialPlatform, false))
binding.addSocialLayout.addView(socialIcon)
(socialIcon.layoutParams as? GridLayout.LayoutParams)?.marginEnd = 48
}
The key is that last line:
(socialIcon.layoutParams as? GridLayout.LayoutParams)?.marginEnd = 48
After the View has been added to the GridLayout, it should have a GridLayout.LayoutParams object that you can alter in code by setting marginStart, marginEnd, etc.

I found solution:
Use android.support.v7.widget.GridLayout
Here programatically set margin and full size horizontally
O activity:
View profileCategoryActive = inflater.inflate(R.layout.profile_category_active, null, false);
categoriesGridContainer.addView(profileCategoryActive);
// set ndroid:layout_columnWeight="1" programatically
GridLayout.LayoutParams params = new GridLayout.LayoutParams(GridLayout.spec(
GridLayout.UNDEFINED, GridLayout.FILL, 1f),
GridLayout.spec(GridLayout.UNDEFINED, GridLayout.FILL, 1f));
params.width = (int) AndroidUtil.dpToPx(this, categoryItemWidth);
params.bottomMargin = (int) tilePreviewLeftRightMarginDp;
params.topMargin = (int) tilePreviewLeftRightMarginDp;
params.rightMargin = (int) tilePreviewLeftRightMarginDp;
params.leftMargin = (int) tilePreviewLeftRightMarginDp;
ConstraintLayout profileCategoryContainer = profileCategoryActive.findViewById(R.id.profileCategoryContainer);
profileCategoryContainer.setLayoutParams(params);
TextView categoryNameTextView = profileCategoryActive.findViewById(R.id.categoryNameTextView);
categoryNameTextView.setText("Ind " + params.width);

Related

ChatKit library : incoming image wrong margins

I'm using ChatKit library (https://github.com/stfalcon-studio/ChatKit/) for a chat feature in my app.
In the message list provided by the library, I also included images messages.
It works fine, but the bubble's layout of the images is ambiguous, as the following picture :
Bubble picture 1 and 3 should be aligned on the right side, but they are stick on the left in the available space for incoming messages.
Note that the default text messages bubbles are displayed correctly on
the right.
I didn't find any attributes for the layout in the library to configure this behaviour.
This is my XML for the message list :
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh_comments"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.stfalcon.chatkit.messages.MessagesList
android:id="#+id/messagesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/input_comment"
app:incomingDefaultBubbleColor="#color/lightGrayRetail"
app:incomingTimeTextColor="#color/white"
app:incomingDefaultBubblePressedColor="#color/lightGrayRetail"
app:incomingDefaultImageOverlayPressedColor="#color/lightGrayRetail"
app:outcomingDefaultBubblePressedColor="#color/pinkRetail"
app:outcomingDefaultImageOverlayPressedColor="#color/pinkRetail"
app:outcomingDefaultBubbleColor="#color/pinkRetail"
app:outcomingTimeTextColor="#color/colorMaterialGray" />
</android.support.v4.widget.SwipeRefreshLayout>
My incoming text message layout layout :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp">
<TextView
android:id="#+id/displayNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/bubble"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:textColor="#color/colorMaterialGray"/>
<de.hdodenhof.circleimageview.CircleImageView
android:id="#id/messageUserAvatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="8dp"
android:src="#drawable/woman" />
<ImageView
android:id="#+id/onlineIndicator"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_alignEnd="#id/messageUserAvatar"
android:layout_alignTop="#id/messageUserAvatar"
android:layout_marginEnd="5dp" />
<LinearLayout
android:id="#id/bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="30dp"
android:layout_below="#+id/displayNameTextView"
android:layout_toEndOf="#id/messageUserAvatar"
android:orientation="vertical">
<TextView
android:id="#id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:id="#+id/incomingTimeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#id/bubble"
android:layout_below="#id/bubble"
android:layout_marginEnd="4dp"
android:text="18:00"
android:layout_marginTop="4dp"
android:textColor="#color/colorMaterialGray" />
</RelativeLayout>
Outcoming layout :
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp">
<LinearLayout
android:id="#id/bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginStart="40dp"
android:orientation="vertical">
<TextView
android:id="#id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="#+id/outcomingTimeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#id/bubble"
android:layout_below="#id/bubble"
android:textColor="#color/colorMaterialGray"
android:layout_marginStart="16dp"/>
</RelativeLayout>
MessageHolder of outcoming :
public class CustomOutcomingMessageViewHolder extends MessageHolders.OutcomingTextMessageViewHolder<Comment> {
private TextView mOutcomingTimeTextView;
public CustomOutcomingMessageViewHolder(View itemView) {
super(itemView);
mOutcomingTimeTextView = itemView.findViewById(R.id.outcomingTimeTextView);
}
#Override
public void onBind(Comment comment) {
super.onBind(comment);
if(comment.getmContent() != null){
if(comment.getmContent().length() > 3){
SimpleDateFormat timeOutput = new SimpleDateFormat("HH:mm", Locale.FRANCE);
String commentPostedTime = timeOutput.format(comment.getmPostedDate());
mOutcomingTimeTextView.setText(commentPostedTime);
}
}
}
}
Any ideas ?
This happened to me without using any MessageHolder, I could fix it by assigning the same width to all images:
int width = Math.round( (float) getScreenWidthHeight().x * 0.8f); // width = 80% of screen's max width
int height = Math.round((float) bitmap.getHeight() / ((float) bitmap.getWidth() / (float) width));
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap), width, height, true);
where getScreenWidthHeight() is:
private Point getScreenWidthHeight(Activity activity) {
Display display = activity.getWindowManager(). getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
Did you check the sender ids in your code to be different for sender and receiver side by the id which is gotten from getId of message model? According to the library you need to determine the senderId in the Adapter initialization:
MessagesListAdapter<Message> adapter = new MessagesListAdapter<>(senderId,
imageLoader);
messagesList.setAdapter(adapter);
Library decides whether to align left or right according to senderIds comparison.
For anyone using the default MessagesListAdapter and ViewHolders, outgoing picture message ImageViews don't have their alignment set, but their parent view width is set to match_parent, which is why the image isn't aligned correctly.
item_outcoming_image_message.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp">
<com.stfalcon.chatkit.utils.RoundedImageView
android:id="#id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:layout_marginLeft="#dimen/message_outcoming_bubble_margin_left"
android:layout_marginStart="#dimen/message_outcoming_bubble_margin_left" />
So, after looking through some of the library code, I found one solution is to simply override onBindViewHolder():
messagesAdapter = new MessagesListAdapter<Message>(senderId, imageLoader) {
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (holder.getItemViewType() == -132) { // -132 is an outgoing picture message
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.itemView.findViewById(com.stfalcon.chatkit.R.id.image).getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_END);
}
}
};
Fixed it by setting a fixed width using ConstraintLayout
val holdersConfig = MessageHolders()
.setIncomingTextConfig(
CustomIncomingTextMessageViewHolder::class.java,
R.layout.item_custom_incoming_text_message
)
Here is my item_custom_outcoming_image_message
<?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:id="#+id/imageMessageContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="8dp"
tools:context=".chatting.ChattingFragment">
<com.stfalcon.chatkit.utils.RoundedImageView
android:id="#id/image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/ic_chat_pick_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent=".8"
tools:srcCompat="#tools:sample/backgrounds/scenic" />
<View
android:id="#id/imageOverlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#id/image"
app:layout_constraintEnd_toEndOf="#id/image"
app:layout_constraintStart_toStartOf="#id/image"
app:layout_constraintTop_toTopOf="#id/image"
tools:visibility="gone" />
<ImageView
android:id="#+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/image"
tools:src="#drawable/ic_message_status_processing" />
<TextView
android:id="#id/messageTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#id/status"
app:layout_constraintEnd_toStartOf="#+id/status"
app:layout_constraintTop_toTopOf="#id/status"
tools:text="12:15" />
</androidx.constraintlayout.widget.ConstraintLayout>

Why are programmatically set weights for Android linear layout columns not working correctly?

I am attempting to create a key for an above pie chart within this Linear layout. However, the weights aren't working properly, and the three columns are split up equally. Does anyone know what may be causing this? Thanks!
Layout XML:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tableLayout1"
android:orientation="vertical"
android:layout_centerHorizontal="true">
<TableRow android:gravity="center"
android:id="#+id/tableRow"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:weightSum="4">
<ImageButton
android:layout_width="0dp"
android:layout_height="100dp"
android:id="#+id/aiButton"
android:layout_gravity="center_horizontal"
android:src="#drawable/barchartwhite"
android:background="#CCAF00"
android:layout_weight="1"
android:scaleType="fitCenter"
/>
<TextView
android:layout_width="0dp"
android:layout_height="100dp"
android:text="TP Activity"
android:id="#+id/textView2"
android:layout_gravity="center|center_vertical"
android:textSize="40sp"
android:background="#CCAF00"
android:layout_weight="3"
android:layout_alignParentTop="true"
android:textColor="#FFFFFF"
android:layout_centerHorizontal="true"
android:gravity="center_vertical" />
</TableRow>
<TableRow android:gravity="center"
android:id="#+id/tableRowSub"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Percentage of Activity per TP"
android:id="#+id/textViewSub"
android:layout_gravity="center"
android:textSize="16sp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp" />
</TableRow>
<TableRow
android:id="#+id/tableRow2"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dip">
<com.shannonsystemsllc.ediconnect.PieChartView
xmlns:chart="http://schemas.android.com/apk/res-auto"
android:id="#+id/piechart"
android:paddingRight="12dp"
android:paddingLeft="12dp"
android:layout_width="300sp"
android:layout_height="300dp"/>
</TableRow>
</LinearLayout>
Code for creating key:
for (int i = 0; i < customers.size(); i++) {
int c[] = {Color.parseColor("#FF4B66"),Color.parseColor("#00A9AC"),Color.parseColor("#70A200"),Color.parseColor("#FAB448"),Color.parseColor("#BFBFBF"),Color.GREEN,custColor,Color.CYAN,Color.BLUE};
TableRow.LayoutParams lp = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT);
TableLayout.LayoutParams tl = new TableLayout.LayoutParams();
final float scale = getActivity().getResources().getDisplayMetrics().density;
int pixels = (int) (30 * scale + 0.5f); //set pixels to dp
TableRow row = new TableRow(activity);
row.setWeightSum(9);
//first row
tl.weight = 1;
lp.weight = 6;
lp.height = pixels;
row.setLayoutParams(lp);
TextView tv1a = new TextView(getActivity());
tv1a.setTextSize(22);
tv1a.setText(customers.get(i));
tv1a.setLayoutParams(lp);
tv1a.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
TextView tv1b = new TextView(getActivity());
tv1b.setTextSize(24);
Float perFloat = ((float)pieChartValues[i]/dataTotal*100);
remainderTotal = remainderTotal - perFloat.intValue();
String percentage;
if (perFloat.intValue() == 0)
{
percentage = ("1%");
}
else
{
percentage = (perFloat.intValue() + "%");
}
lp.weight = 2;
tv1b.setText(percentage);
tv1b.setLayoutParams(lp);
tv1b.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL);
lp.weight = 1;
ImageView tv1c = new ImageView(getActivity());
tv1c.setLayoutParams(lp);
tv1c.setBackgroundColor(c[i]);
row.setWeightSum(3);
row.addView(tv1b);
row.addView(tv1c);
row.addView(tv1a);
row.setId(i);
ll.addView(row);
}
Screenshot:
Set the weight of the contents inside each row as follows:
- For the percentage TextView, set the weight to 3.
- For the ImageView, set the weight to 8.
- For the name Textview, set the weight to 7.
This will result to the entire row to look slightly offset from the centre. Make sure all three views are set to match parent width.
Once you set weights for the views call:
yourLinearLayout.invalidate()
Try this out and see if it works.

Making Recyclerview Fixed Height and Scrollable

SOLVED CHECK ANSWER BELOW...
So I am trying to create a comments functionality for my Android app and I want to display the comments inside a recyclerview and then have a button and textview below the recyclerview to add comments. I want to have the recyclerview a certain height and make it scrollable if there are lots of comments because I dont want the users to have to scroll down the screen to find the add button.
I couldn't get it to work so I was wondering if anyone else had that issue.
I have all the adapter and everything set up, I am just having trouble with the recyclerview.
Thanks.
I prob was not clear on what I was trying to accomplish. I am trying to create a cardview where it will display all the comments and the ability to add a new comment. The recyclerview will take up approx 80% of the height and then the last 20% is for the edittext and button.
My XML (Scroll to last cardview where the recyclerview is)
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/scrollview">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ProfilePageActivity"
>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/profilepagetoolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:minHeight="?attr/actionBarSize">
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:layout_marginTop="35dp"
android:layout_below="#+id/profilepagetoolbar"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:id="#+id/aboutCard">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:gravity="center_vertical"
android:orientation="vertical"
android:layout_alignTop="#+id/aboutCard"
android:focusable="true"
android:focusableInTouchMode="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="-60dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/text"
android:textSize="20sp"
android:text="ABOUT" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/dividers" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp">
<ImageView
android:id="#+id/nameicon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
android:transitionName="appIcon"
android:background="#drawable/ic_account_circle_black_24dp"/>
<TextView
android:id="#+id/Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/secondary"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp">
<ImageView
android:id="#+id/locationicon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
android:transitionName="appIcon"
android:background="#drawable/ic_map_black_24dp"/>
<TextView
android:id="#+id/Location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="11dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/secondary"
android:textSize="15sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp">
<ImageView
android:id="#+id/websiteIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
android:transitionName="appIcon"
android:background="#drawable/ic_explore_black_24dp"/>
<TextView
android:id="#+id/Website"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="11dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/secondary"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:layout_marginTop="35dp"
android:layout_below="#+id/aboutCard"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:id="#+id/writeComment"
android:layout_alignParentTop="false"
android:layout_alignParentBottom="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:gravity="center_vertical"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="-100dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/text"
android:textSize="20sp"
android:text="Comments" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/dividers"
android:id="#+id/divider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<EditText
android:layout_width="244dp"
android:layout_height="wrap_content"
android:id="#+id/editComment"
android:layout_below="#+id/divider"
android:textColor="#color/text"
android:hint="Write a comment..."/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create"
android:id="#+id/btnComment"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:layout_marginTop="20dp"
android:layout_below="#+id/writeComment"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:id="#+id/commentsCard">
<LinearLayout
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="0dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/text"
android:textSize="20sp"
android:text="Comments" />
<android.support.v7.widget.RecyclerView
android:id="#+id/commentsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true" />
</LinearLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
</ScrollView>
The second and first comment are being cut off.
So what my problem was that for some reason, Recyclerview didnt wrap_contents. I did some research (thanks stackoverflow) and found out a lot of people were having this issue and they posted solutions for this issue.
Basically, I had to use a customized linearlayoutmanger to fix the issue.
I will post the solution they posted and links to their questions. thanks for whoever tried to help, I appreciate it.
This is the extra file I needed. And then I had to set my recyclerview to use this layout instead of the default one.
public class MyLinearLayoutManager extends LinearLayoutManager {
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
private int[] mMeasuredDimension = new int[2];
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view != null) {
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
getPaddingLeft() + getPaddingRight(), p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
getPaddingTop() + getPaddingBottom(), p.height);
view.measure(childWidthSpec, childHeightSpec);
measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
}
After that. Change this:
mProductsRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
To this:
mRecyclerView.setLayoutManager(new MyLinearLayoutManager(getApplicationContext(),1,false));
Three new paramets(Context, int Orientation, boolean reverse);
basically, i put 1 for orientation so it shows vertiacally, and false for revers so it shows up how it is ordered in my List.
Links to other people's question with same problem as me.
Nested Recycler view height doesn't wrap its content
Nested Recycler view height doesn't wrap its content
Thanks once again guys. Hope this helps someone else
Add this code in your activity, will set the height of your recycler view to the 90% of user's screen window.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int a = (displaymetrics.heightPixels*90)/100;
recylcerView.getLayoutParams().height =a;
and your comment layout below the your recyclerView
like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/mudit"
>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="5dp"
android:scrollbars="vertical" />
</LinearLayout>
<RelativeLayout
android:layout_below="#+id/mudit"
android:id="#+id/rl_commentWrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:ems="10" />
<Button
android:id="#+id/plusButton"
style="android:buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="Send"
android:textColor="#FFFFFF"
android:translationZ="5dp" />
</RelativeLayout>
</RelativeLayout>
In my situation I had a DialogFragment, in which there are 2 recyclers and 2 horizontal linear layouts with 2 buttons.
Dialog from top to bottom looks like this:
RecyclerView A
Horizontal linear layout X with 2 buttons
RecyclerView B
Horizontal linear layout Y with 2 buttons
On top of that both recyclers size is dynamic.
Recycler A size can change based on user swipes in both recyclers.
Recycler B size can change based on its item click listener.
What I wanted to achieve was to cut the Dialog from top to bottom
and have each of those four views its constant part of the Dialog height.
What worked was to divide it first to 2 separate relative layouts, say lTOP and lBottom. Set lTOP alignParentTop, lBottom alignParentBottom and layout_below lTOP.
Both of them width match_parent, height wrap_content.
Then in each of them create 1 relative (say lINTop) and 1 linear (say lINBottom) layouts. lINTop has recycler, lINBottom has 2 buttons.
Set both lINTop lINBottom width match_parent, height wrap_content.
Set lINTop alignParentTop, lINBottom alignParentBottom and below lINTop.
Set lINTop orientation vertical, lINBottom orientation horizontal.
Set recyclers width match_parent, height wrap_content.
Then i putted this all inside single relative layout with width/height wrap_content and orientation vertical.
Then this inside scrollview with width/height match_parent and orientation vertical.
Then needed a little code magic for setting up recycler in onCreateView:
For Recycler A:
private void setupRecyclerA() {
// use a linear layout manager
RecyclerView.LayoutManager layManUS = new LinearLayoutManager(setupActivity().get());
recyclerA.setLayoutManager(layManUS);
recyclerA.addItemDecoration(new DividerItemDecoration(
setupActivity().get(), LinearLayoutManager.VERTICAL));
recyclerA.setNestedScrollingEnabled(true);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerA.setHasFixedSize(true);
}
For Recycler B:
private void setupRecyclerB() {
// use a linear layout manager
RecyclerView.LayoutManager layManUS = new LinearLayoutManager(setupActivity().get());
recyclerB.setLayoutManager(layManUS);
recyclerB.addItemDecoration(new DividerItemDecoration(
setupActivity().get(), LinearLayoutManager.VERTICAL));
recyclerB.setNestedScrollingEnabled(true);
// set fixed height
DisplayMetrics displaymetrics = new DisplayMetrics();
setupActivity().get().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
// set height to 30 percent of dialog
int a = (displaymetrics.heightPixels*30)/100;
recyclerB.getLayoutParams().height =a;
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerB.setHasFixedSize(true);
}
I didnt invented it, I just combined solutions from many different Stack Overflow questions which I dont even remember now, sorry and thanks to the Creators.
I had a similar problem and solved it with RelativeLayout. I have this layout:
I wanted the top and bottom cardview to stay in place while scrolling the central recyclerView. Tried with LinearLayout and ConstraintLayout but didn't work, the bottom CardView only was shown when I scrolled to the end of the recycler.
This is my code, notice the layout_above, layout_below, and layout_alignParentBottom attributes:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grisMasOscuro">
<androidx.cardview.widget.CardView
android:id="#+id/cv1"
android:layout_width="match_parent"
android:layout_height="50dp" >
<!-- cardview content -->
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/cv3"
android:layout_below="#id/cv1">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/myRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="#+id/cv3"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true">
<!-- cardview content -->
</androidx.cardview.widget.CardView>
</RelativeLayout>
I found another solution.
If you will wrap recyclerview in RelativeLayout, it will solve the problem easily.
Thanks.

2 TextViews, left with ellipsis, right with nowrap, single line

It's the first time I post on this forum, hope it's gonna be fine :)
I'm developping an Android App for public transportation in my city.
Here is what I have
[ |short destination ||next departure| ]
[ |way too long dest...||next departure| ]
Here is what I want:
[ |short destination||next departure| ]
[ |way too long dest...||next departure| ]
Here is a more complete example: s28.postimg.org/5gejnvfd9/actual2.png
Weird coloured backgrounds are just here to easily identify layouts/textviews. You can also ignore the brown line (which is ok).
Basically, I want to have the destination [red background] which have a variable length, and on its right, I want the first departure time [green background]. Everything on one line.
I need to always have the first departure information fully displayed (nowrap). The destination could be wrapped with an ellipsis (...).
[Optional question, how to replace the ellipsis '...' with '.' ?]
Here is the best working code I have so far:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/txtTitleDestination"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#+id/txtTitleFirstDeparture"
android:background="#FF0000"
android:ellipsize="end"
android:maxLines="1"
android:padding="0dp"
android:scrollHorizontally="true"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="#+id/txtTitleFirstDeparture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_alignParentRight="true"
android:background="#00FF00"
android:ellipsize="none"
android:maxLines="1"
android:padding="0dp"
android:textSize="18sp"
android:textStyle="bold"
/>
</RelativeLayout>
I've tried TableLayout and LinearLayour instead of the RelativeLayout, but with no success :(
Any idea how I could do that?
Thanks in advance!
Louloox
[SOLVED]
Just have to lightly modify the valbertos answer:
titleDestination.post(new Runnable() {
#Override
public void run() {
int widthTextViewDeparture = measureTextWidthTextView(titleFirstTime, pContext);
int widthTextViewDestination = titleDestination.getWidth();
int widthTextViewParent = rl_parent.getWidth();
if(widthTextViewDestination + widthTextViewDeparture > widthTextViewParent) {
titleDestination.setWidth(widthTextViewParent - widthTextViewDeparture);
titleDestination.setEllipsize(TruncateAt.END);
titleDestination.setHorizontallyScrolling(true);
}
}
});
Setting the Ellipsis only if necessary makes the text properly truncated.
Before:
Lingolsheim Thiergaten --> Lingolsheim... [1'23"] 21h23
With the modification:
Lingolsheim Thiergaten --> Lingolsheim Thi... [1'23"] 21h23
Thanks again :)
You don't need do it programmatically, ConstraintLayout is a magic!
Just use this code
app:layout_constraintHorizontal_bias="0" align view left
app:layout_constrainedWidth="true" to wrap left text
<?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="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintEnd_toStartOf="#id/rightText"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="|short destination|" />
<TextView
android:id="#+id/rightText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/leftText"
app:layout_constraintTop_toTopOf="parent"
tools:text="|next departure|" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here is result
I found a way to do it using Linear Layout, the trick is not to forget width="wrap_content" for the linearLayout, hope it can help.
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true" />
To do what you are asking for, you must adjust the width of the first view dynamically based on the text width of the second view.
//Code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
final TextView tv_1 = (TextView) findViewById(R.id.tv_1);
tv_1.post(new Runnable() {
#Override
public void run() {
View rl_parent = findViewById(R.id.rl_parent);
TextView tv_2 = (TextView) findViewById(R.id.tv_2);
int widthTextView2 = measureTextWidthTextView(tv_2);
if(tv_1.getWidth() + widthTextView2 > rl_parent.getWidth()) {
tv_1.setWidth(tv_1.getWidth() - widthTextView2);
}
}
});
}
private int measureTextWidthTextView(TextView textView) {
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(getScreenWidth(), View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
textView.measure(widthMeasureSpec, heightMeasureSpec);
return textView.getMeasuredWidth();
}
private int getScreenWidth() {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.x;
}
//Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="#+id/rl_parent"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#348D63">
<TextView
android:id="#+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#BD160B"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="Elsau Elsau Elsau Elsau Elsau Elsau Elsau"
android:textStyle="bold" />
<TextView
android:id="#+id/tv_2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="#+id/tv_1"
android:gravity="center_vertical"
android:minWidth="50dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="[11:30 14:23]"
android:textStyle="bold" />
</RelativeLayout>
<!-- Rest of the layout -->
</LinearLayout>
Use android:maxLines="1" instead of android:singleLine="true" to get rid off the ugly dots -as I did in my example.
Also, I recommend you to use include for the "time" section, instead of repeating the TextViews twice. I’ve just done it like that to keep simple the example.
Maybe you should use a LinearLayout instead of RelativeLayout and use the layout_weight attribute.
<LinearLayout android:orientation="horizontal" ...>
<TextView android:id="#+id/txtTitleDestination" android:layout_width="wrap_content" ... />
<TextView android:id="#+id/txtTitleFirstDeparture" android:layout_width="0dp" android:layout_weight="1" ... />
</LinearLayout>

Textview with long text pushes out other views in GridLayout despite ellipsize=end

My problem is very similar to How to get a layout where one text can grow and ellipsize, but not gobble up the other elements on the layout, but read on below why I can't use TableLayouts as proposed there.
I'm trying to create a listview row that basically looks like this:
| TextView | View 1 | View 2 |
All views contain variable width elements. The TextView has ellipsize="end" set. View 1 should align left of the TextView, while View 2 should align to the right of the screen. So, normally, there would be whitespace between View 1 and View 2. As the text in the TextView grows longer, the TextView should grow, pushing View 1 to the right until there is no more whitespace left. Then, ellipsize should kick in, cutting of the text in TextView and appending an ellipsis ("...") at the end.
So, the result should look something like this:
+----------------------------------------+
| short text [view1] [view2] |
+----------------------------------------+
| long text with ell ... [view1] [view2] |
+----------------------------------------+
I've tried:
TableLayouts, but they seem to make scrolling extremely slow on some devices.
RelativeLayouts, but I either had overlapping views, or view1 or view2 disappeared completely.
GridLayouts, but the TextView always grows until it takes up the whole width of the screen, thus pushing view1 and view2 out of the screen.
This is the GridLayout I tried:
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:layout_gravity="left|fill_horizontal"
android:ellipsize="end"
android:singleLine="true"
android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite ellipsis" />
<TextView
android:layout_gravity="left"
android:text="(view1)" />
<TextView
android:layout_gravity="right"
android:text="(view2)" />
</GridLayout>
View 1 and View 2 are not really TextViews, I just used them in the example to simplify things.
Is there any way to achieve this without using TableLayouts?
EDIT:
As requested, here is my attempt at solving this with a RelativeLayout. The TextView takes up the full width of the screen in this case, so neither view1 nor view2 are visible.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/rl0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:ellipsize="end"
android:singleLine="true"
android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite ellipsis" />
<TextView
android:id="#+id/rl1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/rl0"
android:layout_marginLeft="10dp"
android:text="(view1)" />
<TextView
android:id="#+id/rl2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/rl1"
android:layout_alignParentRight="true"
android:layout_marginLeft="10dp"
android:text="(view2)" />
</RelativeLayout>
I seem to have found a potential solution to prevent a TextView in GridLayout from growing unboundedly and pushing out other views. Not sure if this has been documented before.
You need to use fill layout_gravity and set an arbitrary layout_width or width on the long TextView in need of ellipsizing.
android:layout_gravity="fill"
android:layout_width="1dp"
Works for both GridLayout and android.support.v7.widget.GridLayout
I'm a big fan of LinearLayouts, so here's my suggestion using those:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true"
android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite ellipsis" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(view1)" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="(view2)" />
</LinearLayout>
I will suggest you to play with layout_weight property of your widget
Example:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="10">
<LinearLayout
android:id="#+id/ll_twoViewContainer"
android:layout_weight="8"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/rl0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true"
android:text="Long text" />
<TextView
android:id="#+id/rl1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#id/rl0"
android:layout_weight="1"
android:minWidth="120dp"
android:text="(view1)" />
</LinearLayout>
<TextView
android:id="#+id/rl2"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/rl1"
android:layout_alignParentRight="true"
android:layout_marginLeft="10dp"
android:text="(view2)" />
</LinearLayout>
</LinearLayout>
finally your layout will look like as follow:
+----------------------------------------+
| short text [view1] [view2] |
+----------------------------------------+
| long text with ell ... [view1] [view2] |
+----------------------------------------+
I think you should create custom layout for your purpose. I don't know how to do this using only default layouts/view and make it work for all cases.
The trick which worked for me was to use maxWidth to restrict the width of the first view. You need to do it with Java, here is the basic logic:
firstView.setMaxWidth(parentView.getWidth() - view2.getWidth() - view1.getWidth() - padding * 2);
Not pretty, but it works.
I think there's just a small issue on the layout that could be solved, anchoring the view3 to the right and start from there to force the view to have a delimited area (hence being able to properly set the ellipse):
<?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="wrap_content">
<TextView
android:id="#+id/rl3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="(view2)" />
<TextView
android:id="#+id/rl2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/rl3"
android:text="(view1)" />
<TextView
android:id="#+id/rl1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#id/rl2"
android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite ellipsis" />
</RelativeLayout>
Hope this helps...
Regards!
Try this
<?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:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite ellipsis"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="(view1)"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="(view2)"/>
</LinearLayout>
</LinearLayout>
Currently, all views are centered. You can change android:gravity property to meet your needs. For example, you may want to align view1 right and view2 left in which case last two LinearLayouts would look something like (with 5dp margin on the right and left respectively):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center|right">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginRight="5dp"
android:text="(view1)"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center|left">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginLeft="5dp"
android:text="(view2)"/>
</LinearLayout>
I find my solution for the case number 2 (the one with a long text):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="3" >
<TextView
android:id="#+id/rl0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="3"
android:ellipsize="end"
android:singleLine="true"
android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite ellipsis" />
<TextView
android:id="#+id/rl1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:text="(view1)" />
<TextView
android:id="#+id/rl2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:text="(view2)" />
</LinearLayout>
The real problem is case one, and i didn't try a lot of things for this. I hope it helps (and if i have more spare time, i will try to achieve first one!).
If the views on the right get pushed over by the text by design, you might as well use a ListView instead of a GridView.
You would just need to make the base of the list item layout a RelativeLayout, and set rules like this:
You can set the two views on the right to alignParentRight (using android:layout_alignParentLeft="true"), but make sure the first view stays to the left of the second so it will push itself to the left as the views stretch out.
You can make the TextView on the left align to the left, but stay to the left of the first view (using android:layout_toLeftOf="#+id/viewId") so it won't overlap with the views.
Try using Layout Weight
<TableRow
android:id="#+id/tableRow3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/tableRow2"
android:layout_alignParentBottom="true"
android:gravity="center"
android:weightSum="10"
android:background="#android:color/black" >
<TextView
android:id="#+id/txtInningsTotal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="center"
android:text="0"
android:textColor="#android:color/white" />
<TextView
android:id="#+id/txtTeamOneTotal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2.5"
android:gravity="center"
android:text="0"
android:textColor="#android:color/white" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.2" />
<TextView
android:id="#+id/txtTeamTwoTotal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2.5"
android:gravity="center"
android:text="0"
android:textColor="#android:color/white" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.2" />
<TextView
android:id="#+id/txtGrandTotal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:text="0"
android:textColor="#android:color/white" />
</TableRow>
Here i have taken table row in which there is layout weight sum which is of 10 means that it is 100% width of its parent. and in all its child views i have set width to 0Dp and given weight to 1 or 2. so that it will take up to that percent of total 10. so the layout will be adjusted accordingly screen and also there will be no issue of overlapping.
If i have understood you correctly then this is the answer you wanted.
Hope it Helps!
First, you must layout [view 2] to parent Right;
Again, you reference the reference to the last two layout!
<Relativelayout android:layout_width="match_parent"
android:layout_height="wrap_content"
<TextView
android:id="#+id/view2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeft="#id/view2"
android:gravity="left">
<TextView
android:id="#+id/shortORlongtTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/view1"
android:ellipsize="end"
android:maxLines="1"
android:textSize="18dp"/>
<TextView
android:id="#+id/view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
I had the same problem with the grid layout. what i did is given a fixed width for the text view and also given layout_columnWeight property for each text view then the issue was fixed ,hope it helps ...
<TextView
android:id="#+id/txtName"
style="#style/MyDetailTitle"
android:layout_width="#dimen/detail_length"
android:layout_height="wrap_content"
android:text="#string/app_name"
app:layout_column="3"
app:layout_columnWeight="1"
app:layout_gravity="start"
app:layout_row="1" />
GridLayout is like the other things on Android : flawed by design.
You will need a custom Layout, the following example will allow you to layout things like:
[ label | short text | very long label | short text ]
[ long label | very very very | label | very long text ]
[ | long text | | ]
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public class TwoColumsGridLayout extends ViewGroup {
private final List<List<View>> rows;
private int rowCount = 0;
private int firstColumWidth;
private int secondColumWidth;
private int thirdColumWidth;
private int fourthColumnWidth;
private final List<Integer> rowHeights = new ArrayList<>();
private final List<List<Integer>> cellHeights = new ArrayList<>();
private final List<Integer> firstCellsWidths = new ArrayList<>(4);
private final List<Integer> thirdCellsWidths = new ArrayList<>(4);
public TwoColumsGridLayout(Context context, int rowCount) {
super(context);
rows = new ArrayList<>(rowCount);
}
public void add(Context ctx, TextView l1, View t1, TextView l2, View t2) {
final List<View> row = new ArrayList<>(4);
row.add(l1);
row.add(t1);
row.add(l2);
row.add(t2);
rows.add(row);
this.addView(l1);
this.addView(t1);
if (l2 != null)
this.addView(l2);
if (t2 != null)
this.addView(t2);
this.rowCount++;
}
public int getRowCount() {
return rowCount;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int curLeft = 0;
int curBottom;
int curRight;
int curTop = 0;
int i = 0;
for (List<View> row : rows) {
final int rowHeight = this.rowHeights.get(i);
final List<Integer> rowCellHeights = this.cellHeights.get(i);
final View v0 = row.get(0);
curLeft = 0;
curRight = curLeft + this.firstColumWidth;
if (v0 != null) {
curBottom = curTop + rowCellHeights.get(0);
// Right align
v0.layout(curLeft + this.firstColumWidth - this.firstCellsWidths.get(i), curTop + 7, curRight, curBottom + 7);
}
//
final View v1 = row.get(1);
curLeft += this.firstColumWidth;
curRight = curLeft + this.secondColumWidth;
if (v1 != null) {
curBottom = curTop + rowCellHeights.get(1);
v1.layout(curLeft, curTop, curRight, curBottom);
}
//
final View v2 = row.get(2);
curLeft += this.secondColumWidth;
curRight = curLeft + this.thirdColumWidth;
if (v2 != null) {
curBottom = curTop + rowCellHeights.get(2);
// Right align
v2.layout(curLeft + this.thirdColumWidth - this.thirdCellsWidths.get(i), curTop + 7, curRight, curBottom + 7);
}
//
final View v3 = row.get(3);
curLeft += this.thirdColumWidth;
curRight = curLeft + this.fourthColumnWidth;
if (v3 != null) {
curBottom = curTop + rowCellHeights.get(3);
v3.layout(curLeft, curTop, curRight, curBottom);
}
curTop += rowHeight;
i++;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
// Compute first column width
firstColumWidth = 0;
for (List<View> row : rows) {
final View v = row.get(0);
if (v != null) {
v.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
measureChild(v, widthMeasureSpec, heightMeasureSpec);
final int w = v.getMeasuredWidth();
if (firstColumWidth < w) {
firstColumWidth = w;
}
}
}
// Compute third column width
thirdColumWidth = 0;
for (List<View> row : rows) {
final View v = row.get(2);
if (v != null) {
v.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
measureChild(v, widthMeasureSpec, heightMeasureSpec);
final int w = v.getMeasuredWidth();
if (thirdColumWidth < w) {
thirdColumWidth = w;
}
}
}
secondColumWidth = (parentWidth - firstColumWidth - thirdColumWidth) / 2;
fourthColumnWidth = parentWidth - firstColumWidth - secondColumWidth - thirdColumWidth;
// Clear
this.rowHeights.clear();
this.cellHeights.clear();
this.firstCellsWidths.clear();
this.thirdCellsWidths.clear();
// Compute heights
int height = 0;
for (List<View> row : rows) {
final ArrayList<Integer> rowCellHeights = new ArrayList<>(4);
cellHeights.add(rowCellHeights);
int rowHeight = 0;
// First column
final View v0 = row.get(0);
if (v0 != null) {
int h = v0.getMeasuredHeight();
this.firstCellsWidths.add(v0.getMeasuredWidth());
rowCellHeights.add(h);
if (rowHeight < h) {
rowHeight = h;
}
} else {
this.firstCellsWidths.add(0);
}
// Second column
final View v1 = row.get(1);
if (v1 != null) {
v1.setLayoutParams(new ViewGroup.LayoutParams(secondColumWidth, LayoutParams.WRAP_CONTENT));
measureChild(v1, widthMeasureSpec, heightMeasureSpec);
int h = v1.getMeasuredHeight();
rowCellHeights.add(h);
if (rowHeight < h) {
rowHeight = h;
}
}
// Third column
final View v2 = row.get(2);
if (v2 != null) {
int h = v2.getMeasuredHeight();
this.thirdCellsWidths.add(v2.getMeasuredWidth());
rowCellHeights.add(h);
if (rowHeight < h) {
rowHeight = h;
}
} else {
this.thirdCellsWidths.add(0);
}
// Fourth column
final View v3 = row.get(3);
if (v3 != null) {
v3.setLayoutParams(new ViewGroup.LayoutParams(fourthColumnWidth, LayoutParams.WRAP_CONTENT));
measureChild(v3, widthMeasureSpec, heightMeasureSpec);
int h = v3.getMeasuredHeight();
rowCellHeights.add(h);
if (rowHeight < h) {
rowHeight = h;
}
}
height += rowHeight;
this.rowHeights.add(rowHeight);
}
setMeasuredDimension(parentWidth, height);
}
}
Have fun.
TableLayout will give expected behavior. May cause performance issue as question's author mention, but works great with simple layout. If the row is repeatable and scrollable, consider use gridview instead
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"
android:shrinkColumns="0"
>
<TableRow>
<TextView/>
<View1/>
<View2/>
</TableRow>
</TableLayout>

Categories

Resources