Is it possible to declare a layout with a custom view layout without a wrapping root element? I've got my custom view working but it always matches the parent if I inflate the following layout.xml:
custom_view.xml
<?xml version="1.0" encoding="utf-8"?>
<com.company.ui.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="#dimen/custom_view_height"
android:layout_width="#dimen/custom_view_width" />
dimons.xml
<resources>
<dimen name="custom_view_height">300dp</dimen>
<dimen name="custom_view_width">400dp</dimen>
</resources>
But when the custom view loads and attaches, I see that its calculated size (from onMeasure) is the size of the device's screen.
Do I really need to declare the layout.xml as:
custom_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<com.company.ui.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="#dimen/custom_view_height"
android:layout_width="#dimen/custom_view_width" />
</LinearLayout>
It seems a little pointless as I actually don't care for the LinearLayout nor do I want to remember what I cast into the inflated R.layout.custom_view.
Wow, this is very interesting! Thanks to the following article:
http://www.doubleencore.com/2013/05/layout-inflation-as-intended/
Basically, if you inflate a layout without parent specified, all layout_xxx attributes specified within the root of the layout xml are discarded. You should inflate your layouts as
inflater.inflate(R.layout.your_layout, parent, false);
Also, note that if you pass true (attach to root), the returned element will be the parent element provided. Pay attention to this as it may cause problems when you're expecting the inflated layout to be returned!
Related
I have a layout as indicated below:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
<LinearLayout
android:layout_height="match_parent"
...
The associated activity is like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_login);// here is the layout
}
I'm trying to make it visible in the following way:
LinearLayout layoutActLogin = (LinearLayout) findViewById(R.layout.act_login);
layoutActLogin.setVisibility(View.VISIBLE);
But Android Studio told me that there is an error about R.layout.act_login
findViewById is for views, not layouts.
You should put an ID in your view like:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
<LinearLayout
android:layout_height="match_parent"
...
Then get the view reference and make it visible
View viewActLogin = findViewById(R.id.my_view);
viewActLogin.setVisibility(View.VISIBLE);
You can not change visibility of Layout. you can only change visibility of Views inside.
You can assign id to you view by using android:id tag in you layout. You can read more about this here.
In your case. Just give some Id to your View/ViewGroup, and reference that View from your Activity and using findViewById method and change its visibility.
You're misunderstanding how layouts and views work. Layouts define what is shown on-screen to a user during an activity, set by calling setContentView() within the Activity's onCreate() method. Views are individual elements within the layout, which are accessed with the R.id prefix using findViewById().
In your example you'll need to apply an ID to the root ConstraintLayout (using android:id) to be able to access it:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
Then you can access it with:
ConstraintLayout layoutActLogin = (ConstraintLayout) findViewById(R.id.parent_layout);
layoutActLogin.setVisibility(View.VISIBLE);
EDIT Looking at your code I now realise you want to control the root ConstraintLayout, which makes my answer almost identical to Eduardo Herzer's. Leaving my answer up due to the added explanation at the beginning.
I came across an app, whose layout puzzles me.
Assume two layout XML files, such that one includes the other:
activity_button.xml
<LinearLayout 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" >
<include layout="#layout/button"/>
</LinearLayout>%
button.xml
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/button"
android:onClick="sendMessage">
</Button>
What is the resource ID of the button?
I thought one always had to specify ID via android:id attribute, so I am confused why this layout works. I also checked the R.java ID entry and it seems to be empty.
android:id
Is not mandatory field for a view in the layout xml file. the only two mandatory fields are the width and height of the view.
Think of situations when you want a layout to simply show some title without any business need to change it through the activity life time. for this need you don't need to obtain this view id, and don't need the overhead of creating id for this view
What is the resource ID of the button?
Doesn't have one
I thought one always had to specify ID via android:id attribute
Why did you think this? You often leave off this attribute for the root views of most layouts. (See LinearLayout of your question)
You do not need an android:id if you never expect to find the view using an ID. Since the onClick is defined in the XML, there's really no purpose in finding the button.
I am using a RecylerView inside a layout l1.xml. I am including this l1.xml inside l2.xml using include tag.
I update this RecyclerView after an api call but l2.xml is not showing the updated RecyclerView.
Is there a way to forcibly ask the parent to refresh?
invalidate(), refreshDrawableState(); on the parent layout didn't help?
Is there a smarter way to use a rendered layout in multiple places?
l1.xml
...
...
<LinearLayout
android:id="#+id/feed"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4"
android:background="#color/light_primary_background">
<include layout="#layout/events_list"/>
</LinearLayout>
...
...
events_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/events_recycler_view"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
I update the events_recycler_view after an API call and the events_list.xml is updated but the include in l1.xml is not updated
Yes you can always use LayoutInflater to inflate a view, but the view must have the ids and type matching the id and type defined in your java code.
Check out this link for how to use layout inflater
http://www.programcreek.com/java-api-examples/android.view.LayoutInflater
I have to create a list whose list items have 2 lines of text. I started building a custom list item, but then I discovered the TwoLineListItem component. I wrote this code:
pageFilterResultView=new TwoLineListItem(containerActivity);
pageFilterResultView.getText1().setText("Test");
However, getText1 returns null, and the second line throws a NullPointerException. So I thought I need to use an inflated layout instead of a constructor. The TwoLineListItem documentation specifies I can use the android.R.layout.two_line_list_item resource for the layout, so I changed the code to:
LayoutInflater inflater=(LayoutInflater)containerActivity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
pageFilterResultView=(TwoLineListItem)inflater.inflate(android.R.
layout.two_line_list_item,null);
pageFilterResultView.getText1().setText("Test");
However, this throws a ClassCastException because the layout is actually a LinearLayout. TwoLineListItem inherits from RelativeLayout, so I can't even cast the layout to a higher class in the hierarchy.
So the question is: How do I use TwoLineListItem correctly? Do I have to create my own custom layout for it? If so, what's the point of this component if I still have to do all the work of creating a list item by myself?
How do I use TwoLineListItem correctly?
The TwoLineListItem widget is a facade over two TextViews that have to be provided by you. To use the TwoLineListItem in a ListView's row you'll need a row layout where you have the TwoLineListItem widget with two(at least) TextView children with specific ids(android.R.id.text1 and android.R.id.text2). Something like this:
<?xml version="1.0" encoding="utf-8"?>
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#android:id/text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#android:id/text1"/>
</TwoLineListItem>
Then you can use it in the getView() method like you did:
pageFilterResultView=(TwoLineListItem)inflater.inflate(R.layout.the_layout_file_above,null);
pageFilterResultView.getText1().setText("Test");
Of course you have the possibility of using an included layout file as the child of the TwoLineListItem(as long as you have the two TextViews with the required ids):
<?xml version="1.0" encoding="utf-8"?>
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- the android version of the two line layout -->
<include layout="#android:layout/two_line_list_item" />
</TwoLineListItem>
but this just increases the layout depth and should be avoided.
If so, what's the point of this component if I still have to do all
the work of creating a list item by myself?
Judging by the fact that you can't use this widget programmatically, I don't see the need for this component either.
put your layout code inside try catch block with ClassCastException it will works fine my Friend . .....
I am trying to dynamically add buttons to table rows, but need to alter the style of the buttons based on screen orientation. I have the following "game_answer_button.xml" layout file in both "layout" and "layout-land" folders.
res/layout:
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
/>
res/layout-land:
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
style="#android:style/Widget.Button.Small"
/>
The button layout is being inflated in my activity as follows:
LayoutInflater inflater = getLayoutInflater();
Button button = (Button)inflater.inflate(R.layout.game_answer_button, null);
button.setText(image.getDescription());
However, it seems the default (portrait) layout is selected every time. If the contents of the default layout are replaced with the landscape layout, then the landscape layout is finally rendered. It doesn't seem to be correctly selecting the landscape layout resource via LayoutInflater.
Any ideas on this?
did you check if the configuration of the activity, where the button is used, in the manifest is set to portrait only?
I found the problem. I was loading the dynamic buttons to an ArrayList and merely adding the buttons to my parent view on each configuration change--meaning the button style would have already been inflated when pulling the button objects from "cache". Just another Dev "doh!" moment.