Laying out subviews in a layout programmatically - android

I'm trying to layout views in a relative layout on a tablet, much like a bookshelf. There will be so many across, then a new row is created.
My initial state looks like this:
<ScrollView
android:layout_marginTop="150sp"
android:layout_marginLeft="50sp"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:id="#+id/user_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- Add User Avatar -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="#drawable/user_frame" />
<ImageView
android:id="#+id/demo_image"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="#drawable/add_user"
android:layout_marginLeft="10px" />
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="#drawable/user_name_background"
android:layout_marginLeft="10px" />
<TextView
android:id="#+id/user_name"
android:layout_width="180px"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center_horizontal"
android:text="Add New User" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
I'm fetching records from a database, and for each record I need to place a version of the "add user avatar" section as seen above. I'd like to do 5, then wrap to a new row.
My initial idea was to use a layout inflater and add the views programmatically, using RelativeLayout.LayoutParams to set the layout_toRightOf values.
There must be an easier way though. I've seen lots of applications using the "bookshelf" metaphor.

There are a few options I can think of.
Instead of using a relative layout, why not use LinearLayouts with the horizontal attribute?
Using a TableLayout, much like the LinearLayout
Use a ListView with a custom adapter to fill five 'Add User Avatar's' per ListRow

Laying out views programmatically is fairly simple. I do this for all of my activities / views. I love Android's XML layout concept but find that as soon as the views become at all dynamic based on external data (such as your database) then it gets too complex.
I choose what my outermost layout will be and then only instantiate that layout in the XML. Then in my activity I find the outer layout using the normal find by id call and then use a sequence of add(View) method calls to add my dynamically created views or layouts as needed.
You will need to take into account different screen orientations, pixel densities and sizes. Device Independent Pixels will become your friend. For example, to create an image view, you would load the bitmap, figure out how much to resize it (if needed) and then set it as the drawable for a new ImageView instance, that you then add to the layout.
Sounds like your outer layout will be a scroll view with a vertical linear layout inside, that then has a horizontal layout for each "shelf" that then have up to five image views for each "book"

Related

Android ListView width keeps changing

Firstly, I am new to android so if I have missed something basic I apologise.
I have a page which has two ListViews side by side, both with varying amounts of content. I also have a TextView above the ListViews and another TextView below the listviews. These text view boxes change based on items selected in either of the two ListViews.
These two ListViews sit side by side, taking up half of the screen each, while a Textview sits directly above and directly below, both centred to the page. An image is shown below.
This is the page looking normal on load.
The problem is when I select an item from either list. I have a feeling I am missing some XML properties, but I am not sure which properties or if this is even the case. When an item is selected, let's say from the ListView on the right, the TextView at the bottom is updated with text taken from an array. The ListView also decides to change the width and I am not sure why this is.... I don't want the ListView to change width. I want it to remain taking up half of the page and half of the page only.
This is the page after an item from the right ListView has been selected.
I would also like to keep things in RelativeLayout. I also believe it is only an XML issue and not to do with the adapter or any other code so I will not include that for now. I can include it if required.
Any help would be great. Thanks in advance.
content_titles.xml my activity xml file
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TitlesActivity">
<ListView
android:id="#+id/unlocked_titles_list"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:longClickable="true"
android:layout_below="#+id/current_title"
android:layout_alignEnd="#+id/requirements"
android:layout_marginEnd="26dp"
android:layout_above="#+id/requirements">
</ListView>
<TextView
android:id="#+id/current_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="65dp"
android:text="Current Title: Novice"
android:textSize="24sp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"/>
<ListView
android:id="#+id/locked_titles_list"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignStart="#+id/requirements"
android:layout_marginStart="28dp"
android:layout_above="#+id/requirements"
android:layout_below="#+id/current_title"/>
<TextView
android:id="#+id/requirements"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="34dp"
android:text="temp"
android:textAlignment="center"
android:textSize="24sp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
activity_listview.xml used as the individual rows of the ListViews
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/label"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip"
android:textSize="16dip"
android:textStyle="bold" >
</TextView>
The problems with layout could be caused by ScrollView to be the wrapper
I stumbled upon some note in http://developer.android.com/reference/android/widget/ExpandableListView.html
"...Note: You cannot use the value wrap_content for the android:layout_height attribute of a ExpandableListView in XML if the parent's size is also not strictly specified (for example, if the parent were ScrollView you could not specify wrap_content since it also can be any length. However, you can use wrap_content if the ExpandableListView parent has a specific size, such as 100 pixels."
I removed wrapping ScrollView and linear layout started working properly. Now its only to understand how to wrap the stuff to ScrollView. God help me
But anyway this is really weird behavior. I think that fill_parent is not really correct wording. When using heirarchyviewer tool I always see WRAP_CONTENT and MATCH_PARENT values for layout_width and leayout_height. So probably fill_parent is actually means match_parent which puts me in cognitive dissonance.
You have your layout_width properties set to wrap_content. This means that they could change as the data changes. I would recommend putting your ListViews in a LinearLayout with orientation:horizontal and set the amount of space that each element takes up with layout_weight. Here is a relevant SO question What does android:layout_weight mean?

Which of layout should i use?

I'm confused. I want to show the map and on below of map show 5 buttons. I use RelativeLayout, but the program just show Product button. Why? I'm confused which layout i use (Linear,Relative,Frame or absolute )!! Please help me. and How can i correct this code?
location.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frame"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
android:id="#+id/mapView"
android:apiKey="0cPRv243zM1_S3ydsNg8MJP9_6BfCp642jOhPvQ"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background"
android:layout_gravity="bottom"
android:orientation="horizontal" >
<Button
android:id="#+id/button_home"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="#drawable/home_icon"
android:text="#string/button_home"
android:textColor="#color/text_home" />
<Button
android:id="#+id/button_product"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="#drawable/product_icon"
android:onClick="Product"
android:text="#string/button_product"
android:textColor="#color/text_product" />
</LinearLayout>
</LinearLayout>
To answer your specific problem: Instead of saying that the home button is to the left of the product button, you should say that the product button is to the right of the home button. When a RelativeLayout is inflated, the layout is parsed in a linear way so if view A it positioned relative to view B, view B must come first.
<Button
android:id="#+id/button_home"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="#drawable/home_icon"
android:text="#string/button_home"
android:textColor="#color/text_home"/>
<Button
android:id="#+id/button_product"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/button_home"
android:drawableTop="#drawable/product_icon"
android:onClick="Product"
android:text="#string/button_product"
android:textColor="#color/text_product" />
Add this to the product button and delete the layout_toLeftOf from the home button.
android:layout_toRightOf="#id/button_home"
You can use gravity and alignment to position the home button and then have the other four buttons following it, each one positioned to the right of the one before it.
Good luck
RelativeLayout by default places these 2 buttons together, so you can just see the latter.
And the line
android:layout_toLeftOf="#+id/button_product"
is wrong. #+id creates an id, use #id in such cases.
I would recommend LinearLayout for the situation. Place these buttons in it, and adjust them with some margin.
LinearLayout : LinearLayout is used when we need to arrange the
widgets/views in a horizontal or vertical manner.
The direction of arrangement can be set to horizontal or vertical,
by default it is being horizontal.
TableLayout : If the Layout's widgets/views need to be arranged
in the form of rows and columns, we use this layout object.
This is similar to html tables. The cells can span columns.
The TableLayout do not display its border. We can be made to
shrink and stretch by setting the respective properties of the columns,
"TableRow" is another helper widget which should be used in conjunction
with the TableLayout.
RelativeLayout : Here the position of each of the widgets/view is
in relative/dependent to each other. For example, when a layout is needed
such that it has a text view just to the left of an Edit Textbox, and a button
just below the EditText. The relation between the views are taken care in
one iteration, hence if view B’s position is dependent on view A’s position,
view A must come first in the layout.
FrameLayout : This is a very simply layout which is used to hold a section
of the screen blank, for displaying an item or group of items at run time. All the
elements added in the framelayout will be added to the top left of the screen.
AbsoluteLayout : When there is a need is to specify exact x and y co-ordinate
position of the view, then AbsoluteLayout need to be used. This layout is
difficult to maintain.

What are the different ways to design layouts in android?

I'm fairly new to Android development. I'm wondering what are the different ways that are used to design XML layouts. Ive been using the eclipse drag and drop interface and I've seen http://droiddraw.org/ while doing some searching. Just wondering if there are any other possibly better ways out there to design layouts that professions use because I'm having a hard time with the eclipse interface making complex designs?
First of all check out the android developer site user interface page
http://developer.android.com/guide/topics/ui/index.html
There are basically three different ways you can make an android layout:
XML
http://developer.android.com/guide/topics/ui/declaring-layout.html
You can define a static layout using XML. Perhaps a good way to think of it is a sort of shorthand. It is very easy to declare Views and attributes, and the hierarchical format of XML makes it a bit easier to visualize.
This is a typical layout
<?xml version="1.0" encoding="utf-8"?>
<ViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:attribute="value" >
<ViewGroup android:attribute="value" >
<View android:attribute="value" />
</ViewGroup>
<View android:attribute="value" />
</ViewGroup>
Then you use setContentView(R.layout.layout) in your activity and go about your business.
Java
You can do everything you would do in XML, plus add things like listeners, or do other dynamic things that you cannot in XML. Here is how you might declare a typical layout (ViewGroup is abstract so you would have to use a subclass. The same goes for XML)
ViewGroup parent = new ViewGroup(this);
ViewGroup vg1 = new ViewGroup(this);
View v1 = new View(this);
View v2 = new View(this);
parent.addView(vg1);
vg1.addView(v1);
parent.addView(v2);
v1.setOnAwesomeListener(new AwesomeListener() {
onAwesome(View v) {
doDynamicThings();
}
}
setContentView(parent);
Hybrid
This is the case used most often in my opinion. Declare a layout in XML with an id, like android:id="#+id/v1" then load Views from XML into Java
setContentView(R.layout.layout);
View v1 = findViewById(R.id.v1);
// dynamically change v1
How to design a layout using XML
So the lack of GUI designer tools has left you no choice but to dive into coding up your layout by hand. Good news is that once you get the hang of it you should be able to tackle any layout you wish. Let's look at the building blocks
ViewGroup
First off you need to choose a ViewGroup to define the structure of the layout, or section of the layout. Remember that these can be nested, so design top-down and try to classify sections of the layout based on the form you want them to have. There are two main options:
LinearLayout
As the name implies, useful for arranging items in a line. Choose an orientation, horizontal or vertical, and simply add items. They will be added in top to bottom or left to right ordering.
RelativeLayout
Useful for placing an item in a specific location on the screen. So if you want to put a button in the top-left, or a bar across the top, this is your ViewGroup.
Layout Parameters
Used for defining the width, height, weight, and other aspects of a view.
There are two options for width and height: fill_parent (replaced with match_parent in API level 8) and wrap_content. The view can choose to either fill the parent view's width, or take only the space it needs.
There is another useful layout parameter, unique to LinearLayout, called weight. It is useful for letting views share space in ratios, or letting one view take the space left over after other views in the LinearLayout take their share.
Example
Let's try to design the layout for Google Maps. Pretend it is a layout that I have in my head, and I want to implement it. Here is a screenshot
I will try to break this down:
Looking at it, there is a bar across the top and a map underneath it. I believe this could be implemented with either a LinearLayout or a RelativeLayout. However, the buttons in the bottom right and left scream RelativeLayout, so I will go with that.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TODO:BAR
android:id="#+id/bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true">
</TODO:BAR>
<MapView
android:id="#+id/map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/bar" />
<ImageButton
android:id="#+id/latitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="20dp"
android:layout_marginLeft="20dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical" >
<ImageButton
android:id="#+id/zoom_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageButton
android:id="#+id/zoom_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
Now some explanation. In RelativeLayout you use alignParent[direction] to specify where the view goes. I also wanted some space on the sides, so I used margin[direction] to specify in dp or density-independent pixels. As you can see, wrap_content is used most of the time, so the buttons would acquire the size of the image used on them.
Now everything is defined but the bar at the top. I'm going to break it up into four different Views: The dropdown menu view, the search view, the layers button and the my location button. The way I would like it to work is put the menu at the far left, and the layers and my location buttons on the right, with the search box taking up the remaining space. This sounds like a job for LinearLayout and weight! Here is how I define the bar, which can be inserted into the placeholder above to get the final layout
<LinearLayout
android:id="#+id/bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true" >
<ImageButton
android:id="#+id/dropdown_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="#+id/search"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageButton
android:id="#+id/layers"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageButton
android:id="#+id/my_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Setting the width of the search bar to 0dp means let the other views take what they need, then the weight says take the remaining space.
And there you have it. A recreation of the basic layout for the Google Maps app (minus button images and other niceties like custom views), showing how you might use various layouts and XML fairly painlessly. Hopefully this was useful.
The tool chain is a little weak in this area. I don't really care for DroidDraw, and the Eclipse GUI editor is not very good for anything more than simple layouts. It often renders RelativeLayouts incorrectly for example.
Personally I do almost everything directly in XML. You have to understand how all the different Layout classes work to do anything complex anyway. The only real downside to XML is that all of the extra cruft from tags, attributes, etc. makes for a lot of extra stuff to type, but the editor takes care of most of that for you.

What should my Android Layout look like?

I recently asked a question about how to add a view on top of a view, after asking that I realized I needed to added a better layout to my app before proceeding further.
I was reading Android Layout Tricks but noticed it was specifically for text views and image views. I'm looking to do it with two custom views. So I decided to whip up a quick image in paint to hopefully show more clearly of what I'm wanting to do.
This is how I want my layout to split the views. :
This is how it would look with the views drawn. Obviously the purple and blue boundaries would be the background color (greyish). The data above simply displays the y-intercept of the graph drawn with respective color. (So there would be multiple graph views drawn on top of each other)
So my question is, what would my main content view look like? I assume it would have a Linear layout but I'm rather new to these layouts.
EDIT
Using TextViews I'm able to come up with something similar using the following XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="Data Placeholder"
android:background="#733674"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="20"/>
<TextView
android:text="Graph Placeholder"
android:background="#374F82"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="80"/>
</LinearLayout>
</LinearLayout>
So The only question that really remains is, am I supposed to use TextViews? Meaning in my Activity am I able to add my custom views where these TextViews are? Or am I supposed to add my custom view to the XML?
Ie.
<DataView
android:text="Data Placeholder"
android:background="#733674"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="20"/>
<GraphView
android:text="Graph Placeholder"
android:background="#374F82"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="80"/>
My custom views are written in Java and I'm not sure how I would let the layout know where the views are located if I was to do it this way.
Try this: http://developer.android.com/resources/tutorials/views/hello-linearlayout.html
It has some very useful information which might help you out in regards to layout_weight as Michell Bak mentioned in the comment.
And here's the page for the Hello Views:
http://developer.android.com/resources/tutorials/views/index.html
Not to be rude, but it would be much better for you to peruse these and learn the xml on your own. That way you can actually understand it and be better able to re-create it later.
I was quite overwhelmed at first with all the code I didn't understand (including xml files), but with a little practice it becomes very easy - just time consuming.
The main thing I'm confused about is what kind of View to put in the
layout. In the examples they use TextView or ImageView, but mine is a
custom view
Well, for your "Custom Data View", you would use a LinearLayout with android:layout_width="fill_parent" and android:layout_height="fill_parent" and android:layout_weight="1" and android:background="#BA4AAB" (See http://www.colorpicker.com/)
Then for your Custom Graph View, I would use:
android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="4" android:background="#7D4ABA"
Note the layout_weight and background values I put are kind of guesses, you might have to tweak them some to match what you want.
The two linearlayouts that I mentioned would be inside one larger LinearLayout with android:orientation="vertical"
Then for the data in the top, you would use 4 text Views, and in code, you'd use setText(...) on those text views to put your data in.
In the xml for textview1, you would add android:id="#+id/textview1" then in code add TextView textview1 = (TextView)findviewbyId(R.id.textview1); then textview1.setText(myString);
For the graph in the bottom part, you would use 2 views for the base of the graph, and set there android:layout_width and android:layout_height to whatever suits you using dip, dp, or px units.
For the lines that you draw, I believe you would have to use the canvas class with a bitmap and call canvas.drawLine(...) (see http://developer.android.com/reference/android/graphics/Canvas.html)

How to create layout like this?

I have a horizontal LinearLayout, inside which I have 2 TextViews. Let's say that the LinearLayout's width is 320px. If the TextViews don't fit into the LinearLayout (they are together wider than 320px), I want to somehow achieve this:
The second TextView is fully displayed and is at the right edge of the LinearLayout
The first TextView is only shown partially, only first x characters are visible
What I mean:
[TextView1|TextView2_________________________] // this is normal
[VeryVeryL...|VeryVeryLongTextView2] // VeryVeryLongTextView1 is not fully visible
To get the effect you're requesting in the comments above, you could modify Mayra's solution to something like:
<LinearLayout ...>
<TextView android:layout_width="wrap_content"
android:maxWidth="20dp"
android:layout_height="wrap_content"/>
<TextView android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
I think that will work. Weirdly, the maxWidth param is only present on a couple view classes, but TextView luckily is one of them. You'd think it'd be useful in more cases, so I'm not sure why it's not just available in the default view params.
Specify a specific width for your first textView (i.e, 20dp... note, it is better to use dp than hard coded pixels, to deal with multiple resolutions of devices), give your 2nd TextView a weight of 1. This tells it to take up the remaining space. For example:
<LinearLayout ...>
<TextView android:layout_width="20dp"
android:layout_height="wrap_content"/>
<TextView android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>

Categories

Resources