I want to get height of the linearlayout by the getHeight(), but I find the height was wrong, so I do something to check mistake :
first: int height=linearLayout.getheight() after oncreate() method.
and then linearLayout.setpadding(0,-height,0,0),
but result is the linearLayout content Not completely hidden.
why?
the plan_detail_course_layout_summary.xml file :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f4f4f4"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="课程简介"
android:textColor="#034187"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:orientation="vertical" >
<TextView
android:id="#+id/course_detail_intro_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#929496"
android:textSize="14sp" />
<Button
android:id="#+id/course_detail_intro_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:background="#drawable/bg_btn"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="更多"
android:textColor="#fff"
android:textSize="10sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#drawable/course_intro_border" />
</LinearLayout>
the core code :
LinearLayout layout_course_summary = (LinearLayout)findViewById(R.id.plan_detail_course_layout_summary);
int height=layout_course_summary.getHeight();
layout_course_summary.setPadding(0, -height, 0, 0);
Layout has not completed by the end of onCreate. You can register a layout listener to be notified when layout is completed and the (correct) height is available. For example:
layout_course_summary.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = layout_course_summary.getHeight();
...
layout_course_summary.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
This is the correct approach :
LinearLayout layout_course_summary = (LinearLayout)findViewById(R.id.plan_detail_course_layout_summary);
ViewTreeObserver observer= layout_course_summary.getViewTreeObserver();
observer.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
int height=layout_course_summary.getHeight();
layout_course_summary.setPadding(0, -height, 0, 0);
}
});
Related
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>
I want to show a notification counter like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center"
android:padding="#dimen/_5sdp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:alpha=".5"
android:id="#+id/gvIcon"
android:src="#drawable/ic_person_reading"
android:scaleType="centerCrop"
android:layout_width="#dimen/_70sdp"
android:layout_height="#dimen/_70sdp" />
<LinearLayout
android:id="#+id/llTexts"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
style="#style/gridItemsText"
android:id="#+id/gvText"
android:text="Guten Morgen"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/partNoticeTooltip"
android:orientation="vertical"
android:background="#drawable/bg_tooltip_red"
android:layout_width="#dimen/tooltipWH"
android:layout_height="#dimen/tooltipWH">
<TextView
android:id="#+id/tvCounter"
android:text="4"
android:textColor="#color/white"
android:textSize="#dimen/h6"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
Which has an output like this:
This is my expectation, but with dynamic way. So I wrote this in the setOnItemClickListener of my GridView:
View tooltip = context.getLayoutInflater().inflate(R.layout.part_tooltip, null);
TextView tvCounter = (TextView) tooltip.findViewById(R.id.tvCounter);
tvCounter.setText("" + counter);
LinearLayout llText = (LinearLayout) view.findViewById(R.id.llTexts);
llText.addView(tooltip);
the part_tooltip has exactly the same code but with another layout. And here is the output:
The red layout does not being displayed with full width. What am I missing?
You need to use a global layout listener and also the view tree observer:
ViewTreeObserver mVTO = parentLayoutOfTheViewAddedDynamically.getViewTreeObserver();
mVTO.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if(viewAddedDynamically != null){
int viewWidth = viewAddedDynamically.getWidth();
// any operation based on viewWidth is to be done here
}
}
});
I've been trying to measure the pixel dimensions of a view within a RelativeLayout that's within another RelativeLayout:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="60"
>
...
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/labels_placeholder"
android:id="#+id/player_section_layout"
>
<LinearLayout
android:id="#+id/player_section_background"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
android:weightSum="100">
<!--The view above is what I'm trying to measure-->
<LinearLayout
android:id="#+id/player_section_background_left"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="50"
android:background="#AAAAAA"
android:orientation="horizontal" />
<LinearLayout
android:id="#+id/player_section_background_right"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="50"
android:background="#DD0000"
android:orientation="horizontal" />
</LinearLayout>
<HorizontalScrollView
android:id="#+id/player_section"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_alignTop="#id/player_section_background">
<ImageView
android:id="#+id/waveform_placeholder"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:scaleType="centerInside"
/>
</HorizontalScrollView>
</RelativeLayout>
</RelativeLayout>
I tried calling getMeasuredHeight() and getMeasuredWidth() right after referring to it in onCreateView() of the fragment:
waveformBackground = (LinearLayout)result.findViewById(R.id.player_section_background);
waveformBackground.post(new Runnable() {
#Override
public void run() {
Log.i("bckg_layout_dims", waveformBackground.getMeasuredWidth()+" "+waveformBackground.getMeasuredHeight());
}
});
And it returns 0 for both.
I did hear something about it not working before the view is being drawn, but I don't know when exactly it finishes drawing. Is it after OnCreateView, and if so, can I call it in OnActivityResult?
The problem you are facing is because the view is being drawn after you ask for the height and width. I used a ViewTreeObserver which constantly listens for changes in the views, and can access the measurements after the views has been drawn. Im not sure this is the best solution for your problem but you should look into it. Here's an example:
mTitleContainer.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int toolBarHeight = mTitle.getHeight() + mSubtitle.getHeight() + (int) TOOLBARPADDING;
if (toolBarHeight != mLastTitleHeight) {
CollapsingToolbarLayout.LayoutParams layoutParams = (CollapsingToolbarLayout.LayoutParams) mTitleToolbar.getLayoutParams();
layoutParams.height = toolBarHeight;
mTitleToolbar.setLayoutParams(layoutParams);
mLastTitleHeight = toolBarHeight;
}
}
}
);
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>
I'm trying to create a fragment that lays out a series of custom views dynamically. The main content for this layout is a RelativeLayout nested in a LinearLayout (to center it horizontally), nested in a ScrollView.
The RelativeLayout has a few TextViews and a 9 patch ImageView that is meant to scale with the dynamically added custom views. However, the image (achievements_bgImageView below) is ending up as the size of the screen, and is not respecting the size of its parent RelativeLayout even after I've added the appropriate amount of custom views. The image scales fine when I manually set the size of achievements_mainLayout (see the commented out lines below), but does nothing if I try to let that RelativeLayout's wrap_content handle its own sizing.
The ScrollView IS respecting the size of the RelativeLayout, as all the content is present, it's simply the imageView that isn't stretching to match the content at this point.
Any help would be appreciated... My manual calculations don't seem to be good enough to account for different devices, despite the fact I'm accounting for screen density and I'm manually forcing the RelativeLayout to a constant width.
It's worth noting that the measured size of the RelativeLayout is always equal to the height of the screen, regardless of whether or not the sum of its content is greater or less than that height. So, essentially, WRAP_CONTENT is simply not doing what it's supposed to be doing. I have nothing referencing any edge of of the RelativeLayout, so circular dependencies shouldn't be a problem.
fragment_achievements.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<RelativeLayout
android:layout_width="320dp"
android:layout_height="wrap_content"
android:id="#+id/achievements_mainLayout">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/achievements_bgImageView"
android:src="#drawable/bkg_achievements9"
android:adjustViewBounds="true"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:layout_centerHorizontal="true"
android:scaleType="fitXY"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name Field"
android:id="#+id/achievements_nameTextView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="28dp"
android:layout_marginTop="30dp"/>
<ImageView
android:layout_width="52dp"
android:layout_height="52dp"
android:id="#+id/achievements_avatarImageView"
android:layout_below="#+id/achievements_nameTextView"
android:layout_alignLeft="#+id/achievements_nameTextView"
android:src="#drawable/achieve_avatar"
android:layout_marginTop="5dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Top Moment:"
android:id="#+id/textView2"
android:layout_alignBottom="#+id/achievements_avatarImageView"
android:layout_toRightOf="#+id/achievements_avatarImageView"
android:layout_marginBottom="16dp"
android:layout_marginLeft="4dp"
android:textSize="12dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Me Overall:"
android:id="#+id/textView3"
android:layout_alignTop="#+id/textView2"
android:layout_alignLeft="#+id/textView2"
android:layout_marginTop="16dp"
android:textSize="12dp"/>
<TextView
android:layout_width="52dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="153"
android:id="#+id/achievements_totalPointsTextView"
android:gravity="center"
android:layout_alignTop="#+id/achievements_avatarImageView"
android:layout_alignRight="#+id/achievements_bgImageView"
android:layout_alignEnd="#+id/achievements_bgImageView"
android:layout_marginRight="31dp"
android:textColor="#f7a033"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Moment"
android:id="#+id/achievements_topMomentTextView"
android:layout_alignTop="#+id/textView2"
android:layout_toRightOf="#+id/textView2"
android:layout_marginLeft="5dp"
android:textSize="12dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="153"
android:id="#+id/achievements_overallTextView"
android:layout_alignTop="#+id/textView3"
android:layout_toRightOf="#+id/textView3"
android:layout_marginLeft="5dp"
android:textSize="12dp"/>
</RelativeLayout>
</LinearLayout>
</ScrollView>
AchievementFragment.java
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fragmentView = null;
fragmentView = inflater.inflate(R.layout.fragment_achievements, container, false);
ImageView avatarImageView = (ImageView)fragmentView.findViewById(R.id.achievements_avatarImageView);
...
// Basic Achievement List Setup
RelativeLayout mainLayout = (RelativeLayout)fragmentView.findViewById(R.id.achievements_mainLayout);
AchievementRow currentRow = null;
List achievementTypeList = CampaignManager.sharedManager().sortedAchievementTypeList();
int achievementCount = achievementTypeList.size();
for (int i = 0; i < achievementCount; i++) {
AchievementType achievementType = (AchievementType)achievementTypeList.get(i);
// Every third achievement creates a new row.
if ((i % 3) == 0) {
AchievementRow row = (AchievementRow)inflater.inflate(R.layout.widget_achievementrow, null);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
if (currentRow == null) {
layoutParams.addRule(RelativeLayout.BELOW, avatarImageView.getId());
layoutParams.setMargins(10, 70, 10, 0);
} else {
layoutParams.addRule(RelativeLayout.BELOW, currentRow.getId());
layoutParams.setMargins(10, 10, 10, 0);
}
layoutParams.addRule(RelativeLayout.ALIGN_LEFT, backgroundImageView.getId());
layoutParams.addRule(RelativeLayout.ALIGN_RIGHT, backgroundImageView.getId());
row.setLayoutParams(layoutParams);
row.setId(i+1);
mainLayout.addView(row);
currentRow = row;
}
// Now setup the Button
AchievementButton achievementButton = currentRow.buttonForIndex(i % 3);
achievementButton.achievementType = achievementType;
achievementButton.setOnClickListener(achievementButtonListener);
achievementButton.setVisibility(View.VISIBLE);
CacheManager.sharedManager().fetchAchievementThumbnail(getActivity(), achievementButton, achievementType);
}
// This is the manual scaling of mainLayout
// float scale = getResources().getDisplayMetrics().density;
// float headerHeight = scale * 150.0f;
// float rowHeight = scale * 78.0f;
// ViewGroup.LayoutParams mainLayoutParams = mainLayout.getLayoutParams();
// mainLayoutParams.height = (int)(headerHeight + (Math.ceil(achievementCount / 3.0) * rowHeight));
return fragmentView;
}
Try calling requestLayout on the children.
I recently had a similar problem and was similarly frustrated that things like invalidate and requestLayout seemed to do nothing. What I didn't understand is that requestLayout doesn't propagate down to its children; it propagates up to its parents. To re-measure something that was previously measured, I had to call requestLayout on the View that changed rather than the View I actually wanted to resize.
Android does NOT refresh layout of views with "wrap_content" once it has been displayed.
So if you add a child view, or modify the content dynamically, you're screwed.
I do agree that this is a nightmare and a real flaw in Android UI!
To solve that, I've written a static class that recomputes the sizes and forces the update of the layout for the views with "wrap_content"
The code and instructions to use are available here:
https://github.com/ea167/android-layout-wrap-content-updater
Enjoy!
A simple way to update the size of a View with WRAP_CONTENT is change the visibility to GONE and back to the old visibility.
int visibility = view.getVisibility();
view.setVisibility(View.GONE);
view.setVisibility(visibility);
TESTED ON ANDROID JELLY BEAN IN 2014
MAY NOT WORK ON NEWER ANDROID VERSIONS
Ok, I solved this by manually measuring the RelativeLayout immediately after adding all the views and setting the mainLayoutParams height explicitly. I wish I was smarter and knew why it wasn't automatically doing this correctly in the first place, but oh well.
...
mainLayout.measure(0, 0);
ViewGroup.LayoutParams mainLayoutParams = mainLayout.getLayoutParams();
mainLayoutParams.height = mainLayout.getMeasuredHeight() + 10;
...
I encountered same issue when working with LinearLayout which has wrap_content and one child as TextView match_parent.
To fix this I did this:
Remove the TextView programatically and then add it again.
linearLayout.removeView(textView)
linearLayout.addView(textView)
I know it sounds stupid but it works.
In my case calling invalidate didn't work, only this worked.
Depending on your implementation you need to take care of view index inside its parent
You are getting this problem because you set your layout first and then add its content dynamically.
You are telling the layout to wrap to the content that is not yet their. Try using your layout inflater after you have grabbed your content
You should use NestedScrollView Instead of simple scrollview.
here is my sample Activity Layout code
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F0ECE6"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabIndicatorHeight="6dp"
android:layout_marginTop="-10dp"
app:tabGravity="fill"/>
</android.support.design.widget.AppBarLayout>
<wsit.rentguru.utility.CustomViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
here is code for custom viewpager
public class CustomViewPager extends ViewPager {
private boolean enabled;
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.enabled = false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onTouchEvent(event);
}
return false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onInterceptTouchEvent(event);
}
return false;
}
public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}
}
setup function for viewpager in the activity
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new SampleFragment(), " ");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
here is the sample SampleFragment layout code
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F0ECE6"
android:fillViewport="true"
android:scrollbars="vertical"
android:animateLayoutChanges="true"
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F0ECE6"
android:focusableInTouchMode="true"
>
<Spinner
android:id="#+id/product_category"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#drawable/edittext_rectangle_box"
android:gravity="center|left"
android:textSize="14sp"
android:paddingLeft="10dp"
android:drawableRight="#drawable/ic_down_arrow"
/>
<Spinner
android:id="#+id/product_sub_category"
android:layout_below="#+id/product_category"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center|left"
android:visibility="gone"
android:paddingLeft="10dp"
android:background="#android:color/white"
android:drawableRight="#drawable/ic_down_arrow"
/>
<EditText
android:id="#+id/product_title"
android:layout_below="#+id/product_sub_category"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="15dp"
android:background="#android:color/white"
android:hint="PRODUCT TITLE"
android:singleLine="true"
android:imeOptions="actionDone"
android:layout_width="match_parent"
android:gravity="center|left"
android:padding="10dp"
android:textSize="14sp"
android:textColorHint="#000000"
android:layout_height="40dp" />
<LinearLayout
android:id="#+id/availability_layout"
android:layout_below="#+id/product_title"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/availability"
android:textStyle="bold"
android:paddingBottom="10dp"
android:textSize="14sp"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2">
<Button
android:id="#+id/from"
android:background="#android:color/white"
android:hint="FROM"
android:layout_weight="1"
android:gravity="center|left"
android:padding="10dp"
android:textSize="14sp"
android:textStyle="normal"
android:textColorHint="#000000"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginRight="10dp"/>
<Button
android:id="#+id/to"
android:background="#android:color/white"
android:hint="TO"
android:layout_weight="1"
android:gravity="center|left"
android:padding="10dp"
android:textSize="14sp"
android:textColorHint="#000000"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginLeft="10dp"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/product_location_layout"
android:layout_below="#+id/availability_layout"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/product_location"
android:textStyle="bold"
android:paddingBottom="10dp"
android:textSize="14sp"
/>
<Spinner
android:id="#+id/state_spinner"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#drawable/edittext_rectangle_box"
android:gravity="center|left"
android:textSize="14sp"
android:layout_marginBottom="10dp"
android:drawableRight="#drawable/ic_down_arrow"
android:paddingLeft="10dp"
/>
<EditText
android:id="#+id/area"
android:background="#android:color/white"
android:hint="Area"
android:gravity="center|left"
android:padding="10dp"
android:textSize="14sp"
android:textColorHint="#000000"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"
android:imeOptions="actionNext"
android:layout_marginBottom="10dp"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2">
<EditText
android:id="#+id/zipCode"
android:background="#android:color/white"
android:hint="Zip Code"
android:layout_weight="1"
android:gravity="center|left"
android:padding="10dp"
android:textSize="14sp"
android:textColorHint="#000000"
android:layout_width="0dp"
android:layout_height="40dp"
android:singleLine="true"
android:imeOptions="actionNext"
android:layout_marginRight="10dp"/>
<EditText
android:id="#+id/city"
android:background="#android:color/white"
android:hint="City"
android:layout_weight="1"
android:gravity="center|left"
android:padding="10dp"
android:textSize="14sp"
android:singleLine="true"
android:imeOptions="actionDone"
android:textColorHint="#000000"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginLeft="10dp"/>
</LinearLayout>
</LinearLayout>
<Button
android:id="#+id/tab1_next"
android:layout_width="150dp"
android:layout_height="40dp"
android:text="NEXT"
android:layout_below="#+id/product_location_layout"
android:layout_margin="20dp"
android:layout_alignParentRight="true"
android:background="#color/next_button"
android:textColor="#android:color/white"
android:layout_marginBottom="20dp"
/>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
Set the layout parameters again(width and height), right after adding the view. This worked for me.
if the parent View is a FrameLayout, then do something like this:
ImageView view = (ImageView) LayoutInflater.from(activity).inflate(R.layout.image_object_view, null);
imageObjectsHolder.addView(view);
FrameLayout.LayoutParams param = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
view.setLayoutParams(param);
My problem was fixed by seting layout_width to some specific dp.
So changing from "wrap content" or "match parent"
to
android:layout_width="300dp"
will fix it, but i know it's not solution for all cases. But maybe you have some parent width, so you can apply the width to the textview.
height leave with wrap_content, and it will work.