I'm tryintg to implement Caldroid calendar in my app with few modifications. There is custom ViewPager there:
<com.antonyt.infiniteviewpager.InfiniteViewPager
android:id="#+id/months_infinite_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-10dp"/>
Pager is located under one parent layout. What I wanted was to position the pager inside it's parent using margin or padding. It appears that setting side (left, right) margin or padding makes the app loop somewhere inside ViewPager onMeasure() method.
Can't find any information, that ViewPager can't have a parent with side margin/padding set. onMeasure() contains now only super.onMeasure(widthMeasureSpec, heightMeasureSpec) and It seems that it loops in native libraries for some reason. That doesn't happen without margin/padding
Problem was in the container layout:
<LinearLayout
android:id="#+id/right_page"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:orientation="vertical" >
Just a layout taking half of the screen, so what? It seems the problem was android:layout_width="1dp". Change to android:layout_width="200dp" helped. it doesn't matter if it's 200, 100 or any other number. I think the ViewPager was positioning itself on 1dp first, and then recalculated from percentage width, but just guessing
Related
This is what is causing me many problems:
<RelativeLayout
android:id="#+id/galleryLayout"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="#color/white">
<android.support.v4.view.ViewPager
android:id="#+id/imageViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true" />
<com.viewpagerindicator.CirclePageIndicator
android:id="#+id/circlePageIndicator"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="#dimen/padding_middle"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
Right now this code kind of works only because I've set RelativeLayout's height to 180dp but I don't want to have it this way. I want the whole thing to have height according to ViewPager's child.
There are exactly 2 problems if I set RelativeLayout's height to WrapContent.
Problem 1
ViewPager will expand throughout the whole screen. It just doesn't respect it's wrap_content height attribute. But I've partially solved that with this answer. I'd still appreciate if there's a better solution though.
Problem 2
I want have CirclePageIndicator on the bottom of it's parent (RelativeLayout) so I've added attribute layout_alignParentBottom="true" but now because of this, the RelativeLayout will expand throughout the whole screen for some reason.
So what I'm trying to have is a RelativeLayout which wraps around ViewPager which wraps around it's child. The child is downloaded from web so I can't pre-set it. And on the bottom of that RelativeLayout, I want to have a ViewPagerIndicator.
As for the problem 1 you solved the issue correctly, ViewPager will not wrap its children by default.
As for the second problem, this is a normal RelativeLayout behaviour. If you set its height to wrap_content and add two children, one with layout_alignParentTop="true" and second one with layout_alignParentBottom="true", they will stretch your layout height-wise.
What you should do is: ask yourself if you really need RelativeLayout. If you've provided the whole layout of yours I don't see a need for RelativeLayout (its costly). Vertical LinearLayout would do just fine. If you decide that you really need RelativeLayout, try changing your Indicator's rule from layout_alignParentBottom="true" to android:layout_below="#+id/imageViewPager".
I'm trying to insert a fragment into my application and it's essentially a coloured bar with a few buttons on it. However, whenever I put the fragment onto the main xml file, there's always a bit of a white margin regardless of whatever I do. Here's an sample of some of the fragment code I have in my main xml:
<fragment
android:layout_width="fill_parent"
android:layout_height="50dp"
android:name="sample"
android:id="#+id/sample"
tools:layout="#layout/sample"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_margin="0dp" />
Even though I set the margin to 0dp and the width to fill_parent, there's still a white margin/border on the outside. Is there any way to make a fragment fill the screen widthwise entirely? Thank you!
You have padding and/or margin defined in your parent's ViewGroup that is causing the Fragment's extra spacing. Check the Parent who contains the Fragment and remove the padding :)
I have a Caldroid Fragment that generates a calendar based on a GridView. It takes the complete screen. Then I added an AdView on the bottom of this activity, the problem is that banner covers some cells of the grid so user can't click on them. Basically, I want to set a margin in the inner part of the GridView to allow the user to scroll down the calendar, and when the calendar reach at the end, it continues scrolling for some more margin. This margin will be set with the height of the banner.
I am up to modify the caldroid code if necessary but I can't find how to produce this effect with a GridView. Setting a bottom padding avoids overlapping the AdView but by discarding the whole width, I would like to see the calendar at right and left of the banner when it is not completely scrolled down.
POSSIBLE SOLUTIONS:
-Maybe by adding a margin to the cells produced by the adapter will do it, but I need to know if they are from the last row. using getItemId always returns 0, and the methods getClipBounds and getClipToOutline are limited to API 21.
Use android:clipToPadding="false" with android:paddingBottom= in your GirdView
<GridView android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dip"
android:clipToPadding="false" />
I didn't get why you need inner margins.
Can't you put your GridView and your AdView in the same RelativeLayout
On the GridView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="x"
On the AdView
android:layout_alignParentBottom="true"
x being the height of your AdView
No overlapping, functional scroll.
I have a FrameLayout that loads Fragments by tapping on tabs in a TabWidget. I can't figure out how to make the height of the FrameLayout as tall as its content, so that the whole containing ScrollView will scroll together as one instead of a separate scrolling view.
Here's a visual example of this Fragment's structure:
As you can see, the Frame Layout Visible Height only reveals one row of the Fragment, when in fact, there are a few. I can scroll within the FrameLayout to see the other rows as it is now, but that's not what I'm going for. The FrameLayout is made up of a LinearLayout containing a GridView with their layout_heights set to wrap_content.
I tried hardcoding the height of the FrameLayout to something like 500dp and it works great except for the fact that it's no longer dynamically sized. Would I need to resize the FrameLayout programmatically each time a new image is loaded into the inner content? Is there a layout attribute I can set so it'll stretch its height to match its inner content?
Here's my layout xml file:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="200dp">
<!-- CONTAINS USER INFO AND STATS -->
</RelativeLayout>
<android.support.v4.app.FragmentTabHost
android:id="#android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ffffff">
<TabWidget
android:id="#android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:weightSum="2">
</TabWidget>
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</FrameLayout>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
</ScrollView>
Thank you!
Since I'm going to set a bounty on this, I thought I'd share what I've figured out so far.
In the thumbnails, onSuccess when each image is loaded, I'm calling a function in the GridLayout that holds the images that counts the images and sets the height of the GridLayout. This works fine, although it seems like it'd be a bit inefficient.
What I'm doing is setting the GridLayout height and then calling requestLayout and invalidate on it and it's parent(s). This works, but not as the images loading. It'll work if I go to a different tab and return to the thumbnails, oddly enough. Which makes me think I'm not updating at the right time or on the right object.
Anyway, that said. Does anyone know how to make the height of a GridLayout expand to hold its contents (instead of scrolling) so I can scroll the entire page (including the top section)?
I should also add the GridView layout:
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid"
android:stretchMode="columnWidth"
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false"
android:fastScrollAlwaysVisible="false"
android:fastScrollEnabled="false"
android:numColumns="3"
android:choiceMode="none">
</GridView>
I was in a similar situation but I had a ListView instead of a GridView. You are right in the part when you have to set the height dynamically each time you add an item or if you call notifyDataSetChanged().
THIS CODE IS FOR LISTVIEW WITH DIFFERENT HEIGHT FOR EACH ROW
private void setListViewHeightBasedOnChildren(MyQueueAdapter listAdapter) {
int desiredWidth = MeasureSpec.makeMeasureSpec(
mListView.getWidth(), MeasureSpec.AT_MOST);
int totalHeight = 0;
View view = null;
int i;
for (i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, mListView);
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = mListView.getLayoutParams();
params.height = heightList
+ (mListView.getDividerHeight() * (listAdapter
.getCount() + 3));
heightListComplete = params.height;
mListView.setLayoutParams(params);
}
You need to modify this code according to your needs, you don't need the loop as the height of each row is static in your case. If you need more help let me know.
ALTERNATIVE
If you know the height of the view in dp you can easily convert the dp in px and set the height of your gridview according to number of rows.
When using dynamic sizes you'll run into problems once you put match_parent inside a wrap_content thing. One tries to get a small as it's content and the content tries to be as big as it's parent. Neither side will know how to scale properly in the end.
ScrollView is such a thing that falls in this category. It's a scalable window to it's content so it can't be wrap_content and the content can't be match_parent because it's parent is a virtual infinite space.
Change <ScrollView android:layout_height="wrap_content" to match_parent (or a fixed size).
To solve the size of the content
set the root layout (LinearLayout in your case) of your ScrollView to be a fixed size so it's content can be match_parent again.
use wrap_content all the way.
combine the two: wrap_content until a child defines an absolute size, then match_parent inside there.
The wrap_content route will only work if all the elements in the layout from inner to outer most expand properly based on their content. Nothing can rely on parent bounds unless you add some.
Your content looks rather dynamic in size. So it is likely that you need to use some code to manually set sizes based on content. E.g. if those images inside your tab frame are a GridView (essentially ScrollView with grid content again) you'll need to set it's size manually. More than 1 degree of freedom in wrapping dynamically sizing containers isn't solvable automatically.
Parent of your frame layout is linear layout whose height is wrap_content. also, your framelayout's height is wrap_content. change both of them to fill_parent. using match_parent is more preferred now a days insted of fill_parent
I have an App that has a toolbar at the bottom of the screen and the rest is filled with a custom View (see xml below). Now when I make the App full screen (I tried all possibilities, programmatically and via Manifest.xml), when it's started the whole layout seems to be shifted down by about the height of the notification bar. The buttons in the toolbar are only visible half-way. Sometimes, all of it moves up after a few seconds, or when I click a button in the toolbar.
I'm pretty sure, that it's a problem with my custom view, because I do not get this effect if I replace it with a Button or the like. I guess it must have something to do with the onMeasure method. I don't really know how to implement it, my version is shown below. The custom view is used for drawing inside, so basically it wants to be as large as possible.
Any help would be much appreciated. I searched for several hours already, but no clue yet.
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<com.example.MyCanvasView
android:id="#+id/canvas"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<!-- Buttonbar -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:orientation="horizontal"
android:background="#android:drawable/bottom_bar"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
/>
</LinearLayout>
</LinearLayout>
And this is my onMeasure method:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
You're not taking the mode into account when you're setting your measurement.
The mode of a MeasureSpec can be one of MeasureSpec.EXACTLY, MeasureSpec.AT_MOST, or MeasureSpec.UNSPECIFIED. Simply accepting the size component and setting your measured size to that is appropriate for EXACTLY, but it isn't often the right thing for the others.
Because you're trying to use layout_weight in addition to a height of wrap_content on this custom view, the following is happening:
Your custom view is the first child of the LinearLayout with a height of wrap_content so LinearLayout measures it. Since LinearLayout has been told by the LayoutParams that it should wrap_content, it measures your custom view with a MeasureSpec mode of AT_MOST and a size of the entire available space.
But your custom view is greedy. It decides to take all of the space available. In essence, you have implemented your measurement to treat wrap_content as match_parent.
Now there's no more space left. The lower button bar gets measured accordingly but it's not done yet, there's a child with weight. In a LinearLayout any space left over after all normal measurement is complete is divided among the weighted children according to their weight values. This isn't the behavior you want.
When you use weight to fill available vertical space like you're doing in this layout, you normally want to set the layout_height to 0dip. This will make LinearLayout skip the first measure pass on that child and only use the weighted measurement pass to measure your view, giving it the remaining available space.
I found the reason for the described behaviour. I had set the view to be focusable in touchmode via setFocusableInTouchMode(true) in the onCreate() method. As soon as I removed this, it works fine. Thanks to adamp though -- your description of what goes on during layout and measuring was very interesting.
But that leaves me with the problem that I do not receive any key/button clicks any more :-(