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 . .....
Related
I have a recycler view with the following layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/color_primary"/>
</RelativeLayout>
I have a problem because during a test I have a moment where the recycler view show two views with the same text and I need to check if one of them is visible.
The code to match the view is the following:
onView(withId(R.id.title)).check(matches(withText("Test")));
And espresso is failing because it is finding more than one view that matchs the matcher criteria.
How can I match the specific view that I need?
One possible solution is to set a different tag in each row and use this tag to match with espresso.
Let's say the data that is being shown is persisted in the database. You can use the model id as the tag, with this you will have each row in the recycler view with a unique constraint that you can use in the matcher.
The code would be something like this:
onView(allOf(
withId(R.id.title),
allOf(
isDescendantOfA(withTagValue(is((Object)model.getId())))),
withText(model.getTitle())))
.check(matches(isDisplayed()))
Since you need to use the text inside the matcher, you can check if the view is visible to add a clause to your test.
You can read an article explaining this here: https://medium.com/tech-track/validating-views-by-tag-with-espresso-50d3f47b14a7
I've spent a lot of time looking for a way to get the default header state indicator (▲/▼) to show on my ExpadanbleListView header item (something I would expect to be trivial). Eventually, I've found mention of the android:attr/listSeparatorTextViewStyle style. So I tried this in my group view layout XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
style="?android:attr/listSeparatorTextViewStyle"
android:id="#+id/firmwareItemHeader"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="50dp"/>
</LinearLayout>
But the result is wrong - the indicator overlaps with the text:
How to fix this?
Of note: the ExpandableListView has android:indicatorRight="?android:attr/expandableListPreferredChildIndicatorRight".
As you can see, my header view layout is a primitive single TextView, and it's going to stay that way. I'll happily use a default view with an indicator instead of my own XML, if such a view exists (I couldn't find one).
One can set a custom #drawable indicator via android:groupIndicator attibute of the list view, but again, I can't find any default value.
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
My code currently requires a reference to a ListView in another XML file and activity. I have tried using the include keyword as so:
<include layout="#layout/cleareditems"/>
However, when I do this it merges the two layouts and you can see everything in clearedItems. What would I do just to reference that View and change it?
Thanks!
here is an example
<PATH_TO_YOUR_CLASS.YOUR_CLASS
android:id="#+id/search"//we give some name to it
android:layout_width="match_parent"
android:layout_height="wrap_content" />
and you should use merge tag, so the layout are not duplicated
<merge xmlns:android="http://schemas.android.com/apk/res/android">
//YOUR CUSTOM VIEW ELEMENTS, in this case its called search from above
</merge>
Assumptions about the list (updated):
It will not contain more than 10 list elements (the list elements are defined by the xml layout below).
The height of every element is unknown, because the list element contain a LinearLayout that can have up to 20 child views (see xml below).
XML Layout of the list element:
<?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:"horizontal">
<!--
This LinearLayout is going to contain one or more
Views which will be added progammatically on runtime.
The number of children views added to it depend on the
data to be displayed, and the only assumption that can
be made is that there's will be no more than 20 child
views for one particular instance of this LinearLayout.
-->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="25dp"/>
<ImageButton
android:layout_width="25dip"
android:layout_height="25dip"
android:layout_gravity="center|top"
android:layout_marginLeft="-25dp"/>
</LinearLayout>
Questions:
Does it make any sense to use a ListView for a layout that has such freedom
in its structure (like the one above), and still being able to make use of the
convertView as passed in to the ListView#getView(...)?
As an alternative, would it be wrong to put all the list elements in an outer
LinearLayout and put this within a ScrollView? By doing this, I wouldn't get
caching abilities of the ListView, but maybe it wouldn't be so heavy given the
assumptions about the list? (see top). (Any pointers on how to make this alternative look and feel like a ListView? I'm thinking of applying standard colors and selectors etc.)
If you know some of your 10 elemets will be the same, you could use
getItemViewType(int position)
To be sure that the convertView will match your item type convertView