So far, my app is pretty simplistic and small. It has a few buttons here and there, but I can see it quickly getting out of hands with a ton of buttons. So my problem really, my activity_main.xml looks ridiculously ugly. It has a bunch of tags, so I was wondering, what's the "correct" way to generate buttons when you have a lot of these?
Use XML do define views. I would always recommend you to use xml, even if there are 20 Buttons.
Alternativly you can also set the button programmatically in code and at them to your layout. Just set the layout parameters and you are done.
Otherwise (if you have a list of many buttons and you need to scroll) a ListView or GridView would a good choice.
To make things cleaner in your XML, you can use include to reference other XML which defines a generic button with all its common properties.
So the button would be defined under genericbutton.xml placed in the layout folder:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick" />
</merge>
And then your main activity_main.xml will have something like this for three buttons:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include
android:id="#+id/button1"
layout="#layout/genericbutton" />
<include
android:id="#+id/button2"
layout="#layout/genericbutton" />
<include
android:id="#+id/button3"
layout="#layout/genericbutton" />
</LinearLayout>
But in this case, you either set the same text for the buttons inside the genericbutton.xml or one by one in Java code. You cannot set it in the include tags.
Related
I have a linear layout that I normally add ImageViews to programmatically, but I'd like to render better previews inside Android Studio when looking at layouts.
I can't use tools:src as mentioned here because I don't have any ImageView at all in the XML until runtime.
As a really naive approach, this works visually in Android Studio:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include tools:layout="#layout/some_sample_layout"/>
</LinearLayout>
If #layout/some_sample_layout is then another LinearLayout:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop"
tools:src="#tools:sample/backgrounds/scenic" />
</LinearLayout>
But while it displays OK in Android Studio, it fails to compile:
Execution failed for task ':app:mergeDebugResources'.
> main_layout.xml: Error: ERROR: [44 68 44 68 25] must include a layout file:///main_layout.xml
Ideally I think that I'm looking for:
some way to add an ImageView directly to the main LinearLayout but mark the whole view as "ignore unless tools" or
to be able to "swap" in the body of the LinearLayout somehow.
Is this possible with tools at the moment?
I think the cleanest and most universal approach for displaying dynamically inflated views in AS designer would be to use <include /> tag, quite similar as in your example.
Our <include /> tag must have layout property, to make the app buildable. We can omit it by attaching dummy layout with <merge /> root. Because it has no children, no views will be inflated.
Universal lt_merge_empty.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="0dp"
android:layout_height="0dp">
<!--
Empty merge tag, so we can use <include/> to show dynamically inflated layouts in designer windows
For example:
<include
tools:layout="#layout/your_inflated_layout"
layout="#layout/lt_merge_empty"
/>
-->
</merge>
Then use it in your layout:
<include
tools:layout="#layout/your_inflated_layout"
layout="#layout/lt_merge_empty"
/>
Please note: for some reason, tools:layout must be placed above layout property, otherwise it won't be rendered.
Edit: This approach is more universal than #Sina's one bacause usually you will want to display the exact layout that you are dynamically inflating, so obviously you can't change its android:visibility to gone.
You must include a layout so include it but set its visibility to gone or set ImageView sizes to zero while having what you like with tools attributes. Here I've done both.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="#layout/some_sample_layout"/>
</LinearLayout>
<LinearLayout
android:visibility="gone"
tools:visibility="visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
tools:layout_width="100dp"
tools:layout_height="100dp"
tools:scaleType="centerCrop"
tools:src="#tools:sample/backgrounds/scenic" />
</LinearLayout>
I am thinking to create a layout whose height is much more than the screen height. OK say, the parent layout is LinearLayout and it is set to provide a vertical scrollbar automatically.
Inside the parent layout, there are many controls (listview, gridview, listboxes, editboxes etc). To make it easier for design, can I put listview in one xml, gridview in one xml, listbox in one, editbox in one etc and then later use some defined function to concatenate and allocate them all in the parent layout ?
If this is not possible, how can I design a layout that has many controls allocated that design screen can't fit at design time ?
xml_common.xml
code:
<?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="#dimen/common_topheader_width"
android:background="#drawable/topheaderfor9patch" >
<ImageView
android:id="#+id/xml_common_header_imageLogotop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="2dp"
android:layout_marginRight="#dimen/common_left_right_margin"
android:src="#drawable/qarrow" />
</RelativeLayout>
///////////////////////////////////////////
Main_view.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/mainbg"
android:orientation="vertical" >
<include layout="#layout/xml_common" />
</LinearLayout>
you can set different images as per your choice set in runtime of common view.
I need your advice regarding my design and if you have a better idea (or you agree with me) that it is good. for some reason I have a feeling it is a "stone age programming style" but lets see.
Basically I have my xml relative layout. In the center (vertical and horizenatlly). I want to display "either" 3 buttons OR 3 texts depending on some user input. So what I did is the following:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipChildren="false"
android:clipToPadding="false" >
<RelativeLayout android:id="#+id/Buttons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<Button1 .../>
<Button2 .../>
<Button3 .../>
</RelativeLayout>
<RelativeLayout android:id="#+id/Texts"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<TextView1 .../>
<TextView2.../>
<TextView3.../>
</RelativeLayout>
</RelativeLayout>
Depending on the user input in the code I set visibility to either Visible or Invisible
Is this alright? and if not what do you suggest?
What you need is View.GONE, and View.VISIBLE.
With View.GONE - the layout doesn't occupy any space (almost as if it didn't exist at all). If you use View.INVISIBLE, to the user, the view (buttons, or text in your case) will not be visible, but they will still be there on the screen, thus shifting the other view (buttons, or text) up or down (the view won't be in dead center).
TIP: You can use 'android:layout_centerInParent' instead of 'android:layout_centerHorizontal' and 'android:layout_centerVertical'.
In my opinion, what you have done may be primitive, but it is simple, which is good :) But if you still want some options and make life complicated, then
Put each of the blocks in a separate xml and use include.
Make 2 views and then use ViewFlipper to flip them based on user requirements.
But for the simple requirement that you have, I think u r doing fine.
The include option would work something like this,
layout_1.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Buttons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<Button1 .../>
<Button2 .../>
<Button3 .../>
</RelativeLayout>
layout_2.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Texts"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<TextView1 .../>
<TextView2.../>
<TextView3.../>
</RelativeLayout>
your main_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipChildren="false"
android:clipToPadding="false" >
<include layout="#layout/layout_1" />
<include layout="#layout/layout_2" />
</RelativeLayout>
The include helps you in making reusable layouts and also helps in keeping your xml files grow out of proportions, specially when you have complicated UIs.
First option is:
You can add all the three buttons or textviews in Linearlayout and center it in parent by using android:layout_centerInParent.
Second option is:
You can center the middle button out of all the three buttons and adjust the other two buttons with respective to the middle button. Same way we should also repeat this for textviews. In this option, we should make all the three views visibility to View.GONE explicitly.
I'm new to Android and I wonder why I can't drag and drop things like buttons to the display in the main.xml Graphical Layout? It seems like it's locked or something else that I can't figure out on myself. Help is preciated! Thanks!
EDIT: This is my code in xml file
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="#string/hello"
/>
You are not able to do so because you don't have a Layout in your XML. Given here is an example as to how to build a basic layout. You can also refer to the Relative Layout tutorial or Linear Layout tutorial for more details, as these are widely used layouts.
Given below is the sample code for your 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" >
<TextView
android:id="#+id/textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
</LinearLayout>
You can replace Linear Layout with Relative Layout at your convenience. But do keep in mind that you can't use the graphical layout without having a layout. To drag and drop a layout, refer the image below:
Hope this helps.
If that's your code, then it seems that you might be trying to drag elements into the TextView since it is filling the entire layout. Try to remove the TextView and see if you are then able to drag and drop elements again. Either that or change it to:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello"
/>
I am a begginer Android Studio to. I have same problem about drag and drop in design screen (in GUI). I solve the problem by using "res/layout/content_main.xml" (left side of the screen). It works! but ı am not sure that is it the right way :)))
Drag and drop the elements onto the Outline area instead of the display itself.Worked for me.
I have been trying for a few days now to make my layouts more efficient by converting from using several levels of nested LinearLayouts to one RelativeLayout and have come across a few problems that I haven not been able to find a workaround for...
I have searched the Android beginners group and this site and have not been able to find anything that would help me solve the problem.
I read on one of the blogs that you can combine layouts with merge and include tags. So what I have is a main layout file with a RelativeLayout root element. Inside of that I have 5 include tags that reference 5 different xml layout files that each have a merge element for the root (all of my merge files are the same except for the ids in them).
I am running into two problems, which I will explain after posting a simplified version of my layout code:
Sample Main Layout File:
<?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"
android:background="#drawable/translucent_gray" >
<include
android:id="#+id/running_gallery_layout_id"
layout="#layout/running_gallery_layout" />
<include
android:id="#+id/recent_gallery_layout_id"
layout="#layout/recent_gallery_layout"
android:layout_below="#id/running_gallery_layout_id" />
<include
android:id="#+id/service_gallery_layout_id"
layout="#layout/service_gallery_layout"
android:layout_below="#id/recent_gallery_layout_id" />
<include
android:id="#+id/process_gallery_layout_id"
layout="#layout/process_gallery_layout"
android:layout_below="#id/service_gallery_layout_id" />
</RelativeLayout>
Sample included merge file:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
style="#style/TitleText"
android:id="#+id/service_gallery_title_text_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:text="#string/service_title" />
<Gallery
android:id="#+id/service_gallery_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_below="#id/service_gallery_title_text_id" />
<TextView
style="#style/SubTitleText"
android:id="#+id/service_gallery_current_text_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/service_gallery_title_text_id"
android:layout_above="#id/service_gallery_id" />
</merge>
I am running into two problems:
1) The android:layout_* attributes seem to be ignored when used in the include tag and all of the merged layouts are displayed on top of each other. According to this post (http://developer.android.com/resources/articles/layout-tricks-reuse.html) "any android:layout_* attribute can be used with the <include /> tag"
2) Since I couldn't get this working I decided to try adding an android:layout_below attribute to the first TextView item in each merge layout file, meaning that each merge file would be referencing an id from another merge layout file... For the most part this actually worked and my layout looks fine. However, I get an error on one of the android:layout_below attributes saying that it can't find the id I specified... I have double and triple checked the ids to make sure they were correct. The weirdest part is that I used the AutoFill feature to put the id in the attribute in the first place.
If anyone has any suggestions or workarounds I will be more than happy to try them out. Also, if anyone can think of a way for me to just have one merge xml layout file instead of 5 that would be greatly appreciated. I couldn't find a way to do that because I need to have access to each item in the merge layout files at runtime...
There is an issue with the include tag. Check: https://issuetracker.google.com/issues/36908001
To fix it, make sure you overwrite BOTH layout_width and layout_height when including, otherwise everything will be ignored.
See the more highly voted answer below. Mine is woefully outdated
i can address one issue Justin raised: inability of RelativeLayout to manage positioning of an include (at least in this simple case, on a 1.6 emulator)
CommonsWare suggests wrapping the includes in a unique parent container, but does so in order to assist addressing & scoping identically named Views within Justin's includes
Each would have to have a
unique parent container, and you would
call findViewById() on that container
(ViewGroup) rather than on the
Activity.
In fact, you also must do it in order to get RelativeLayout to behave as expected:
This works (footer is well positioned):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<include android:id="#+id/header" layout="#layout/header"
android:layout_alignParentTop="true" />
<WebView android:id="#+id/webView" android:layout_below="#id/header"
android:background="#77CC0000" android:layout_height="wrap_content"
android:layout_width="fill_parent" android:focusable="false" />
<LinearLayout android:layout_alignParentBottom="true"
android:layout_height="wrap_content" android:layout_width="fill_parent">
<include android:id="#+id/footer" layout="#layout/footer" />
</LinearLayout>
</RelativeLayout>
This does not (footer is floating at top of screen):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<include android:id="#+id/header" layout="#layout/header"
android:layout_alignParentTop="true" />
<WebView android:id="#+id/webView" android:layout_below="#id/header"
android:background="#77CC0000" android:layout_height="wrap_content"
android:layout_width="fill_parent" android:focusable="false" />
<include android:id="#+id/footer" layout="#layout/footer"
android:layout_alignParentBottom="true" />
</RelativeLayout>
The bare footer include will not align to bottom of parent, without the surrounding LinearLayout.. I wouldn't call this expected behavior.
Additionally, the WebView appears to attach itself nicely to the header by ID, but I believe this to be illusion, due to it simply flowing below the header vertically. I also tried to set a button right above the footer include, but it got all floaty and wrong, too
RelativeLayout had more problems in 1.5, but i still like it :)
Man, this is old, but it seems to come up at the top of searches, so I'm going to comment.
I think the trick here is that the <merge> tag combined with the <include> tag essentially remove any sort of "parent" view group at that level. So then, who exactly are you asking to "layout_below" someone else? No one. There is no view at that level.
The <merge> tag takes the child views and pops them right into the parent of the <include> tag. You must therefore ask the children in the layout you're including to anchor themselves accordingly.
For positioning to work on RelativeLayout you need to set the layout_* parameters in the include file, not in the main layout file. That way
main_layout.xml
<RelativeLayout
android:id="#+id/header"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
....
</RelativeLayout>
<RelativeLayout
android:id="#+id/footer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
.....
</RelativeLayout>
<include layout="#layout/content_layout" />
content_layout.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:id="#+id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#id/footer"
android:layout_below="#id/header" >
....
</RelativeLayout>
</merge>
This is obviously not what us developers want, but it's the only solution I've found to avoid duplicating xml
The android:layout_* attributes seem
to be ignored when used in the include
tag and all of the merged layouts are
displayed on top of each other.
My guess is that you cannot reference, from layout rules, android:id attributes that are defined on <include> elements, only ones that are on "real" widgets and containers.
Also, if anyone can think of a way for
me to just have one merge xml layout
file instead of 5 that would be
greatly appreciated.
Simple: put them all in one file.
I couldn't find a way to do that
because I need to have access to each
item in the merge layout files at
runtime
Whether you have one <include> element or 1,000, all of the contents should be accessible at runtime. One exception is if you have duplicated android:id attributes -- you would need to properly scope your findViewById() calls to get the right one, just like you have to when getting widgets from a ListView row.
If you can create a sample project that uses 2+ merge files where you can demonstrate that the contents are not accessible at runtime, let me know.
try :
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:showIn="#layout/activity_home">
In my case, the layout which I was trying to include starts with <merge tag. When I changed it to a layout, say <RelativeLayout it worked. Below is the illustration.
WORKING
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:showIn="#layout/activity_home">
NOT WORKING
<merge xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:showIn="#layout/activity_home">
I had the same problem and even defining layout_width and layout_height it didn't work.
The problem was that the layout I was including had tags and after removing them, everything worked like a charm.
I suppose that merge is not a layout tag and because of that, it cannot receive positioning and size parameters. Since everything you define in is transferred to the inner parent layout, the settings just were throw away.
TL:DR: Just remove the tags, move the xmlns definitions to a real layout viewholder and you should be good.
Before:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<...ui.component.BorderCardView
android:layout_width="112dp"
android:layout_height="32dp"
app:cardCornerRadius="4dp"
app:cardUseCompatPadding="true">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="#drawable/ic_logout"
android:tint="#color/divider" />
</...ui.component.BorderCardView>
</merge>
Working:
<...ui.component.BorderCardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="112dp"
android:layout_height="32dp"
app:cardCornerRadius="4dp"
app:cardUseCompatPadding="true">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="#drawable/ic_logout"
android:tint="#color/divider" />
</...ui.component.BorderCardView>