LinearLayout with weight-attributes on children inside a ScrollView - android

The usual question regarding ScrollViews seems to be how to use fillViewport to let the ScrollView stretch to the whole screen. My problem is similar, but going the other way :)
I got a LinearLayout that contains multiple elements. All except one element have a fixed height, the special one is an ImageView that should stretch to fill the remaining space. This works fine :)
Now I want to put the LinearLayout into a ScrollView, as some of my elements should expand at runtime (e.g. click on "more"-icon that expands a TextView). In the unexpanded version I would like to have all elements fit on the screen, as if the ScrollView wouldn't exist.
Unfortunately, when wrapping the ScrollView around the LinearLayout, the ImageView is scaled to maxSize und the screen does not fit the screen. Do you have any ideas how to achieve my goal?
I reproduced the problem in an example app to share it with you:
<ScrollView 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"
android:fillViewport="true" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="#ffff0000"
android:scaleType="fitCenter"
android:src="#drawable/background" />
<TextView
android:layout_width="fill_parent"
android:layout_height="80dp"
android:background="#ff00ff00"
android:text="element 2"
tools:context=".MainActivity" />
<TextView
android:layout_width="fill_parent"
android:layout_height="80dp"
android:background="#ff00ff00"
android:text="element 1"
tools:context=".MainActivity" />
</LinearLayout>
</ScrollView>
Here are the screenshots from the two versions:
The one above is the Layout with ScrollView (notice the scrollbar and cropping on element 1), the one below without.
Update: The original height of the image in the image-view is bigger than the screen. So it should be downscaled (that's why it has weight 1 and scaleType set).
Solution: The following code solved the problem for me (based on Luksprog answer)
Main Activity (excerpt, change of layout is induced by click on ImageView):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scrollView = (ScrollView) findViewById(R.id.scroller);
frame = (FrameLayout) findViewById(R.id.frame);
layout = (LinearLayout) findViewById(R.id.layout);
final ImageView image = (ImageView) findViewById(R.id.image);
image.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ImageView image = (ImageView) findViewById(R.id.image);
frame.removeView(layout);
scrollView.addView(layout);
image.getLayoutParams().height = image.getHeight();
}
});
}
Layout XML file
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ScrollView
android:id="#+id/scroller"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:fillViewport="true"
>
</ScrollView>
<LinearLayout
android:id="#+id/layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="#ffff0000"
android:scaleType="fitCenter"
android:src="#drawable/background" />
<TextView
android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="80dp"
android:background="#ff00ff00"
android:text="element 2"
tools:context=".MainActivity" />
<TextView
android:layout_width="fill_parent"
android:layout_height="80dp"
android:background="#ff00ff00"
android:text="element 1"
tools:context=".MainActivity" />
<TextView
android:layout_width="fill_parent"
android:layout_weight="0.1"
android:layout_height="0px"
android:background="#ff00ff00"
android:text="element 3"
tools:context=".MainActivity" />
</LinearLayout>
</FrameLayout>

As I said in my comments, I don't know if what you're trying to do is possible at the xml level. One option would be to modify your current layout and add a root FrameLayout to which you'll, initially, add the ScrollView and above it, the LinearLayout. In this position the ImageView will behave as you want as the user didn't modify the layout. When you need to show more in your layout you'll detach the LinearLayout from the view hierarchy(with removeView) and attach it to the ScrollView(with addView). You'll reverse this when the user goes back to the initial layout.
This will make the ImageView to have different heights when making the views switch so you'd want to get the height of the ImageView and re set it when doing the switch. To get the height, you could do it in a listener or using the post method in onCreate(as the views haven't been laid out yet at that moment). Also, remember that the user could turn the phone, I don't know if this will affect your layout, but take it consideration.

Firstly i tried running your code and it didn't cause any issue for me. The scrollView did not show up although the image was scaled to a ScreenHeight-160dp height which i expected because you have used weight 1 for this imageview.
I would suggest that you remove the weight and give height as wrapcontent. In that case the Imageview will just enclose the Image. When it becomes bigger in size, automatically scrollview come into use if the total heights of all screen contents is more than the screenheight.

Related

Android Textview with width 0 is forcing content to disappear below it

I have a TextView whose width should not exceed the ImageView above it. Both image and text are downloaded from server and I don't know their dimensions (can't make assumptions either). I went through the logic to wrap the text content using this SO post.
Here is my layout XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLL"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout android:orientation="vertical"
android:id="#+id/LL1"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:width="0dp"
android:text="This is a string whose width may or may not be more than the image downloaded" />
</LinearLayout>
<TextView android:background="#android:color/holo_red_dark"
android:id="#+id/text2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Second Text"/>
</LinearLayout>
With this code, the TextView at the end (text2) does not even show up. There are 2 solutions to this issue :
Apply android:maxLines="5" to the text1. Problem with this approach is that Text1 view would always be 5 lines high (I understand 'lines' is not a unit of height, but that's what I see visually). So if the text content is just one word, there would be a big white space below. And then text2 shows up.
Change topmost linear layout (parentLL) to RelativeLayout. text2 can then be used with alignBelow=LL1. This works as expected. But I cannot migrate the topmost view to RelativeLayout, because this view is from a library not in my control. I can only modify LL1 and it's children. Due to my code, other views below (like text2) are suffering (by not showing up).
There is a third approach for setting the textview as a compound drawable on ImageView. I guess that might work (haven't tested), but my requirement is to show the TextView if image download has failed (which can be detected only after a while). So I need to have a TextView. Also, my LinearLayout LL1 can have other children too.
I would request for some help understanding :
Why is my code not showing up the content below the textview 'text1'? With width=0 on textview it seems to set the height of the parent to be match_parent.
How is RelativeLayout able to handle this smoothly ? Can I replicate any of that behavior in TextView's onMeasure ? Assume I have callbacks to detect image has been downloaded, and I can get image width also.
I think what you are running into is a conflict of setting the width and height but not setting the layout weight, which is a key factor in how Linear Layouts work. If you add one more vertical LinearLayout in there and then move #id/text2 into it, you should be set. You'll need something like the following (obviously modified to your specs, this was just a quick test). Note my use of android:layout_weight,
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView3" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView2" />
</LinearLayout>
</LinearLayout>
Which splits the screen in half vertically as shown in this picture,
Photo of resulting layout
I had to wrap the TextView in a RelativeLayout, which was wrapped by a LinearLayout. Not happy with this solution, but this is the only way for now.

How to set layout height to one screen height except actionbar and status bar, in scrollview

I have a layout in a scrollview and I add another layout to the end of the first one. Actually I am trying to make a one page design and the rest of the other views will appear after scrolling. I tried to put linearlayout1 and linearlayout2 to another view but it didn't work. Also I set scrollview android:fillViewport="true" but it made the scrollview in screen size.
I've added an image of what I want, but it could also be one view, I mean lin1 and lin2 together.
I can set width and height for one phone but I want to do this for each screen. For example like yahoo weather app. They have done one layout for first view and start another view from the end of screen. I tried so many things but I couldn't imagine how to put layouts. Could you help me?
Thanks for your help
Here is what I want
Here is I tried:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scroller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/linearlayout1"
android:background="#android:color/holo_purple"
android:layout_width="match_parent"
android:layout_height="350dp" >
<TextView
android:text="LinearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="#+id/linearlayout2"
android:background="#android:color/holo_blue_bright"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="vertical">
<TextView
android:text="LinearLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:background="#android:color/holo_green_light"
android:layout_width="match_parent"
android:layout_height="350dp">
<TextView
android:text="LnearLayout3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</ScrollView>
But unfortunately I couldn't configure this for each screen size.
enter image description here
Just try this.
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/action_bar"
Instead of hardcoding the height as in:
android:layout_height="250dp"
Set android:layout_height="0dp" and use
android:layout_weight="25"
And also in the other layout use weight. Weight works like this, if you have 3 components in your container, set the weights to let's say 1, 2 and 3 => they will take in that order 1/6, 2/6 and 3/6 of the container. 6 being the sum of 1,2,3. So here instead of using heights as 350 and 250, you can set them to 0 and use weights 2.5 and 3.5 or 25 and 35.

LinearLayout does not return onFling?

I expect to display one picture each time and horizontally swipe to another picture through onFling(). The problem is I have to use ScrollView to wrap my ImageView so as to get response from onFling. If I use Linearlayout to wrap the ImageView, nothing happens when I swipe. I don't want to use scrollview because the picture can be scrolled vertically though it is the exact screen size. How can I achieve it? Below is my layout.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/iv_tutorial"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</ScrollView>
I fixed it by adding an attribute android:longClickable="true" to the LinearLayout.

Using ScrollView for scrolling an ImageView

I'm trying to create a layout which consists of one long image which should be scrolled vertically only.
I.e. - it should stretch to take the whole screen width and stretch for the full height.
My layout does this, but it creates strange gaps before and after the image. Each gap takes about 2/3 of the screen and can be scrolled down.
How can I remove the gaps so that only the ImageView appears on the screen?
My activity XML is like this:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="0dp" >
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
tools:context=".HelpActivity" >
<ImageView
android:id="#+id/imageHelp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:src="#drawable/tutorial_with_text" />
</LinearLayout>
</ScrollView>
Found the solution: For future reference:
Use android:adjustViewBounds="true" on the ImageView

Dynamically adding views to RelativeLayout inside ScrollView

I am trying to add dynamically created several RelativeLayouts into a LinearLayout which is inside a RelativeLayout, which is inside a ScrollView. When the total height of the all views exceed the size of the phone screen, all views are displayed correctly. But when the total size of dynamically added views is not enough for filling the screen, only the first RelativeLayout element is shown and the others are not displayed in the screen. I am really hopeless and do not understand why.
Here is the code to dynamically populate views inside linear layout:
LinearLayout commentsLayout = (LinearLayout) findViewById(R.id.comments_layout);
LayoutInflater inflater = (LayoutInflater)
this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for(Comment c: commentsList) {
RelativeLayout layoutItem = (RelativeLayout) inflater.inflate(
R.layout.list_item_comment, null, false);
TextView tv = (TextView) layoutItem.findViewById(R.id.textView);
ImageView iv = (ImageView) layoutItem.findViewById(R.id.imageView);
// set tv's text
// set iv's image and onclicklistener, nothing fancy here, everything goes well
commentsLayout.addView(layoutItem);
}
Here is list_item_comment.xml:
<RelativeLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/white"
>
<ImageView
android:id="#+id/imageView"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_alignParentLeft="true"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
/>
<TextView
android:id="#+id/textView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="10dp"
android:textSize="16sp"
android:layout_toRightOf="#id/imageView"
/>
</RelativeLayout>
And here is the xml file for this activity:
<RelativeLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/main_layout"
>
...
<ScrollView
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:id="#+id/scrollView"
>
<RelativeLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/relativeContainer"
>
...
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/comments_layout"
/>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
And the screenshots:
Without sufficient layouts: (INCORRECT, needs to show 3 comments)
With enough layouts: (CORRECT ONE, screen is filled)
I just need to show all three comments in the first case :/ Thanks in advance.
instead of fill_parent, try changing the layout_height of the <RelativeLayout> of your list_item_comment.xml to wrap_content.
Also, why do you need another <RelativeLayout> inside your <ScrollView> of the xml of your activity. The LinearLayout is sufficient to do what you want your activity to look like. Maybe you can just remove it.

Categories

Resources