"Workspace" child views not filling height on Google "iosched" app - android

I'm playing around with the iosched app from Google I/O 2011. Looking at the ScheduleFragment, I'm testing a different view on the Workspace children for flinging the pages back and forth. However, I'm having trouble getting my child views to fill the parent. I added several background colors and some padding to show where everything is laying out. Here's my test...
I added a red background color to the "Workspace" item in fragment_schedule.xml like this...
android:background="#cc0000"
Then, instead of using blocks_content.xml for the child view, I created my own pending_content.xml that is simply a green-background LinearLayout (with fill_parent for height) and a blue-background TextView (also with fill_parent for height) with a simple text line.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00cc00"
android:padding="5dip"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/text_view"
android:background="#0000cc"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Pending Content"
android:textColor="#ffffff"
/>
</LinearLayout>
I add my view just like the I/O app has "days"...
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_schedule, null);
mWorkspace = (Workspace) root.findViewById(R.id.workspace);
ShootView view = new ShootView();
view.index = mViews.size();
view.rootView = (ViewGroup) inflater.inflate(R.layout.pending_content, null);
view.label = "Pending";
mWorkspace.addView(view.rootView);
mViews.add(view);
And here's what I see when I view it on the device:
You'll see that the red Workspace fills the available parent space, but the green LinearLayout does not. What am I missing?

The problem is that during your inflation step:
view.rootView = (ViewGroup) inflater.inflate(R.layout.pending_content, null);
You lose the LayoutParams defined in your XML, and your view actually ends up with default layout parameters.
What you need to do is provide a root and simply not attach the inflated layout to the root during inflation:
view.rootView = (ViewGroup) inflater.inflate(R.layout.pending_content, mWorkspace, false);
This will allow the layout inflater to construct an appropriate set of LayoutParams for your child view from the parsed XML attributes.

I figured out a solution. I started debugging the onLayout in Workspace.java. In the child.layout function call, I changed child.getMeasuredHeight() to this.getMeasuredHeight() to use the height of the workspace instead.
Seems to work fine for the case of a page that is shorter than the workspace height as well as a child that is bigger (a long ListView) that is larger than the height of the workspace.

Related

Fixed element when using TileView in Android Studio

I am building an activity within Android Studio which uses the TileView library by moagrius to build a layout that can be panned and zoomed, which is all working just fine. I am trying to add an element to the activity which stays fixed at the bottom of the screen and not be affected by the scrolling and zooming of the TileView.
Points to Note:
The TileView and content inside of it are all generated and placed programmatically. It does not use an XML layout.
The element I'm trying to place is an Image. It needs to be in the bottom center of the viewport, and can preferably be reused easily in other activities.
Things I've Tried:
I've tried placing the menu button in its own XML file and tried to use the include attribute on the main XML layout file and inflate that via Java. No luck. The bottom menu is still affected.
I've tried programatically generating the menu button, adding it to a new Relative (tried Linear too) layout, and adding it with parameters to make it sit at the bottom. This got it to appear and stay at the bottom, but it was still affected by zooming and panning.
I've tried using a FrameLayout to add the tileview on top (tried bottom too) of the Relative or Linear layout containing the button, and it was still affected.
I've tried a few other concepts but they didn't work either.
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/res"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
app:theme="#style/Theme.AppCompat">
<include layout="#layout/menu"/>
</RelativeLayout>
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="#+id/bottompanel">
<RelativeLayout android:layout_height="match_parent"
android:layout_width="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true">
<ImageView
android:id="#+id/imageView3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/bottombarclosed"
app:srcCompat="#drawable/bottombarclosed" />
</LinearLayout>
</RelativeLayout>
</FrameLayout>
activity.java
// Initialize TileView, set it's size, and add the detail level (background)
TileView tileView = new TileView(this);
tileView.setSize(5600, 5000);
tileView.addDetailLevel(.15f, "tile-1-1.png", 200, 100);
/*
Generate content for the TileView here.
*/
RelativeLayout rl = new RelativeLayout(this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.CENTER_IN_PARENT);
/*
Add the generated content to the Relative Layout for the TileView here.
*/
// Make a new instance of the layout inflator.
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
// Inflate the bottom menu FrameLayout and save for later.
FrameLayout bm = (FrameLayout) inflater.inflate(R.layout.menu, (ViewGroup) findViewById(R.id.bottompanel));
// Adds the TileView content to the ViewGroup (scaleable, so it can be affected by zooming and panning.)
tileView.addScalingViewGroup(rl);
// Remove the parent from the bottom panel so it can be reassigned. (It crashes without this)
((ViewGroup)bm.getParent()).removeView(bm);
// Add the bottom menu to the tileView without scaling (so it SHOULDN'T be affected by zoom and panning)
tileView.addView(bm);
// Set the content view to display
setContentView(tileView);
Update
I got it to stay in the right position by switching
FrameLayout bm = (FrameLayout) inflater.inflate(R.layout.menu, (ViewGroup) findViewById(R.id.bottompanel));
to
RelativeLayout bm = (RelativeLayout) inflater.inflate(R.layout.menu, (ViewGroup) findViewById(R.id.menulrel)); // menurel is an immediate child of the beforementioned FrameLayout
and by adding the TileView to the RelativeLayout instead of the other way around, and setting the content view to the RelativeLayout (bm). Now the issue is, the menu shows for a second, then is hidden when the TileView updates... Hmmm....
I finally found the answer! I'm just posting it here just in case somebody else stumbles across this issue.
I changed the inflator back to the FrameLayout as it was in the original post.
FrameLayout bm = (FrameLayout) inflater.inflate(R.layout.menu, (ViewGroup) findViewById(R.id.bottompanel));
Then added the tileView to the FrameLayout.
bm.addView(tileView);
Used the full view to locate the Relative Layout container of the menu (parent of the ImageView), then called bringToFront on it.
bm.findViewById(R.id.menurel).bringToFront();
This next step is the MOST IMPORTANT part. You MUST invalidate the RelatieLayout for it to stay present on the screen. Otherwise it fades as the TileView updates and re-renders.
bm.findViewById(R.id.menurel).invalidate();
Then lastly, add set your content view to the new FrameLayout with the other views included.
setContentView(bm);
I hope this helps somebody out in the future!

ListView - Center Cell Views Horizontally w/o ListView Height Wrap_Content

I am currently having some formatting issues with Android's ListView. After looking through several questions on SO I did not find any proper solutions.
I have a ListView (used for navigation) including one or more views (actual navigation items). What I want to achieve is - the ListView uses up the whole vertical space (heigth set to match_parent) and the cells are centered vertically in this ListView.
Simply setting the gravity to center_vertical for the ListView does not do the trick. I currently can only achieve this look if I wrap the ListView in another view (which has set the gravity to center_vertical) and change the ListView's height to wrap_content. But this seems not to be the perfect solution as the resulting measuring operations (the adapter’s getView method is called multiple times for the same position) have a performance impact, even if applying a proper holder concept for the navigation items. Is there any solution to this issue?
ListView (gravity does not work):
<ListView android:id="#+id/lvNavigation"
android:layout_width="#dimen/navWidth"
android:layout_height="match_parent"
android:gravity="center_vertical" />
ListView with workaround (bad performance):
<LinearLayout android:layout_width="#dimen/navWidth"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical">
<ListView android:id="#+id/lvNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Navigation item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_weight="match_parent"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingLeft="#dimen/horizontalMargin"
android:paddingRight="#dimen/horizontalMargin">
...
</LinearLayout>
Listview is probably a bad thing to use for this purpose. I think what you should do is use a recycler view with a custom Layout Manager
In particular you probably want to override onLayoutChildren
I did a quick search and could not find a library that does this for you already.
Alternatively, if you have elements where you can predict the height you can add a header view that is blank and set the height so that the list items will appear centered.
So something like
ListView lv = getListView();
LayoutInflater inflater = getLayoutInflater();
ViewGroup header = (ViewGroup)inflater.inflate(R.layout.header, lv, false);
header.setLayoutParams(new AbsListView.LayoutParams(<width>, <height>));
lv.addHeaderView(header, null, false);

Pull down view (menu) from ActionBar

I need to implement a pull-down view that has a "handle" in right-most part of the ActionBar. It should be full width and open with an animation when the handle is clicked, and additionally the handle itself should be draggable. minSdkVersion is 8
Regarding the pull-down functionality itself, I found that SlidingDrawer isn't going to fit the bill, since it has been deprecated as of API v17, and it can only be opened from bottom to top. The control SlidingTray seems to overcome that issue. I haven't tested it thoroughly but but it seems to work as expected.
Now to the main issue. Is it even possible to display the view in such a manner? I have tried to set a custom view for the ActionBar, where the inflated XML looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<my.package.drawer.SlidingTray
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:content="#+id/content"
android:handle="#+id/handle" >
<ImageView
android:id="#+id/handle"
android:layout_width="88dp"
android:layout_height="44dp"
android:src="#drawable/ic_launcher" />
<Button
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</my.package.drawer.SlidingTray>
</RelativeLayout>
Now, the SlidingTray view itself is functioning as expected when I put it in the activity/fragment layout (can drag the handle and click it to open/close the tray), but when inflating the layout above inside the ActionBar, and upon pressing/dragging the handle, the Tray only moves a few pixels before stopping - it doesn't go beyond the ActionBar bounds. This is the main issue - can the view go beyond the ActionBar itself (over the activity displayed below), and if so - how?
Since no one answered, I'll post how I resolved the issue.
After some inspecting with hierarchyviewer, I saw that the ActionBar was in a LinearLayout and as such, it wouldn't be possible to extend a child of it outside of the ActionBar bounds. So I decided to get the root (decor) view and attach the modified version of SlidingDrawer there. Here is the excerpt:
ViewGroup decor = (ViewGroup) getWindow().getDecorView();
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View drawerContainer = inflater.inflate(R.layout.sliding_drawer, null);
drawer = (SlidingDrawer) drawerContainer.findViewById(R.id.drawer);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
decor.addView(drawerContainer, params);
Since adding a view this way displays it behind the Status bar, I also added a container view with top padding of 25dp so that the handle and content are displayed beneath it.
Note: if you are using the SlidingMenu library, you need to do this in onPostCreate(), because the library also does this and will place your view behind all of the other content.

Adding new widget controls dynamically to an existing layout

i've seen this question added on the stack but the information hasn't been helpful or successful yet, so i remain quite not sure.
The gist of what I'm trying to do:
I have a layout defined in xml, some_details_view.xml for example.
setContentView(R.layout.some_details_view);
It has a bunch of text views laid out using a parent relative layout, a linear header layout, a linear footer layout, a middle scroll layout that contains a relative layout that hold some label - value type of text views.
And at the bottom of the scroll view relative layout, I currently placed a frame layout as a place holder.
On create of the corresponding activity, I set text in respective text views with data handed over from previous activity; basic stuff.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/white" >
<LinearLayout
android:id="#+id/header"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true" >
...some header content
</LinearLayout>
<LinearLayout
android:id="#+id/footer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical" >
..some footer content
</LinearLayout>
<ScrollView
android:id="#+id/scroll"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/footer"
android:layout_below="#+id/header"
android:layout_margin="5dip" >
<RelativeLayout
android:layout_width="fill_parent"
android:id="#+id/relativeScroll"
android:layout_height="wrap_content" >
...text views in relative layout
<FrameLayout
android:id="#+id/placeholder"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/moreInfoValue" />
</RelativeLayout>
</ScrollView>
</RelativeLayout>
After setting up text views for the given data, I use an async task to get some additional data that I want to show as a history list type of thing at the bottom of the static form layout. There could be 0 or more items so I either add 1 or more text views or none at all.
In the post execute, which I understand to run on the main UI thread, I try to find an exiting container Layout/view group and add either a new Linear Layout to which I add new text Views, or just add the new text views directly to the existing container layout.
here's the latest thing I tried:
ViewGroup mContainer = null; //defined as member variable of activity class and instatiated in on create
mContainer = (ViewGroup)findViewById(R.id.placeholder); //set in on create
LinearLayout ll = new LinearLayout(context); //on post execute of async task
ll.setOrientation(LinearLayout.VERTICAL);
mContainer.addView(ll); //add a new linear layout to an existing container layout
//add some new text view widgets items dynamically
for(NewDisplayItem item : items)
{
TextView tv = new TextView(context);
tv.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
tv.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
tv.setText(item.getSomeText());
ll.addView(tv); //add text view to new linear layout
}
When the UI loads I don't see new items added to my layout after stepping through and watching the controls get added using the code above.
Not sure what it is but something doesn't seem right about this approach in addition to the fact that it's not working. When the activity loads up, all the static views are setup and in view. I pop up a loading dialog, step through the async task stuff and I guess expect to see the dynamic controls add to the layout one by one?
First of all textView.setWidth(int) takes as parameter the width in pixels.
Second you should also set your layout parameters on the LinearLayout you are adding.
The way you should set LayoutParams is as follows :
ll.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
the same for yout TextViews.
Ovidiu Latcu has a good answer. A good question is: is there a reason why you aren't using a ListView (which btw there ARE cases where what he's doing works better)? A ListView has a lot of mechanisms to help you keep from running out of RAM

Problem building layout programmatically

I am building something like a ListView, but I'm rolling my own because I want to do some custom stuff and have more control than using ArrayAdapters.
So I've defined part of my layout in XML, including one LinerLayout inside a ScrollView. My goal is to bind to that Linearlayout in code, then insert additional RelativeLayouts inside the LinearLayout using no XML, just code.
Here is my XML:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ListScroll"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:id="#+id/ListHolder"
android:layout_height="400px"
android:background="#323232"
>
<!--Here is where I want the RelativeLayouts to go... -->
</LinearLayout>
</ScrollView>
Then in code, I'm trying to add RelativeLayouts, each 50px in height, to the LinearLayout, the one above that has a height of 400px.
//The parent container - is defined above in XML.
itemContainer = new LinearLayout(context);
itemContainer = (LinearLayout)findViewById(R.id.ListHolder);
Layouts = new ArrayList<RelativeLayout>();
Layouts = LoadWithRelativeLayouts();
for(RelativeLayout listItem: Layouts){
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, 40);
listItem.setLayoutParams(params);
itemContainer.addView(listItem);
}
Each one of the layouts in the array has a text view in it that says "Test". When I step through the code, there are 10 elements in the array, and all of the textviews are there, so I would expect to see the 400px LinearLayout filled with 10 Relative layouts one after another, each with 50px height (and fill_parent width) reading "Test" - but all I see is one, as if only one got added, or they are all positioned on top of one another.
Getting screenshot now...
When you add something to a layout, you have to use layout params of that kind. So as you're adding to a LinearLayout, you should use LinearLayout.LayoutParams.
Then you'll probably also need to set your LinearLayout orientation to vertical, because right now the items you don't see are all in a row offscreen at the right :)
Try adding android:orientation="vertical" to the LinearLayout holding the RelativeLayouts.

Categories

Resources