RecyclerView does not display any items when it is in a layout - java

I have a navigation drawer activity that contains a fragment that contains a RecyclerView. This RecyclerView works perfectly if it is the only component in this fragment, but I want to add a button above the RecyclerView and therefore insert the RecyclerView and the button in a LinearLayout. But then the RecyclerView has disappeared or no longer shows any elements.
How can I embed this RecyclerView in a layout?
RecyclerView works with this one:
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
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:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:name="com.company.myapp.ui.ItemFragment"
app:layoutManager="LinearLayoutManager"
tools:context=".ui.home.HomeFragment"
tools:listitem="#layout/fragment_item" />
RecyclerView has disappeared in this one:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete Item" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:name="com.company.myapp.ui.ItemFragment"
app:layoutManager="LinearLayoutManager"
tools:context=".ui.home.HomeFragment"
tools:listitem="#layout/fragment_item" />
</LinearLayout>
See complete project here: https://github.com/jriegraf/MyApp

You have this code in HomeFragment:
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
if (mColumnCount <= 1) {
recyclerView.setLayoutManager(new LinearLayoutManager(context));
} else {
recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
}
recyclerView.setAdapter(new MyItemRecyclerViewAdapter(DummyContent.ITEMS, mListener));
}
This is your problem. Once you wrap RecyclerView into LinearLayout, this
if (view instanceof RecyclerView)
isn't true any more, because now, view's type is LinearLayout.
If the view doesn't remove the recyclerView, you can ommit the if statement, and change this line:
RecyclerView recyclerView = (RecyclerView) view;
into:
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list);

Related

RecyclerView doesn't Show Data When Adding two fragments to FragmentManager

I have 2 fragments with recyclerview. InteractionsFragment and its copy InteractionsFragmentCopy (exact same replica of InteractionsFragment). When I try to add them, only the one that gets added first its recyclerview data is displayed, the other fragment's recyclerview data is blank as shown on the screenshot:
---Activity code---
public class HomeActivity extends AppCompatActivity {
private InteractionsFragment interactionsFragment = InteractionsFragment.newInstance();
private InteractionsFragmentCopy interactionsFragmentCopy = InteractionsFragmentCopy.newInstance();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container1, interactionsFragment).show(interactionsFragment).commit();
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container2, interactionsFragmentCopy).show(interactionsFragmentCopy).commit();
}
}
---Layout file---
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activities.HomeActivity"
android:background="#color/Blue">
<FrameLayout
android:id="#+id/fragment_container1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_margin="16dp"
android:orientation="vertical"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent=".9"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="parent"
android:background="#color/Yellow">
</FrameLayout>
<FrameLayout
android:layout_margin="16dp"
android:background="#color/Yellow"
android:id="#+id/fragment_container2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent=".9"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="parent">
</FrameLayout>
</LinearLayout>
Any idea why this is happening?
I have the answer here
answer
It turned out that since I'm using viewpager inside the fragment then I hade to change the viewpager adapter instantiation from:
InteractionsFragment.ViewPagerAdapter adapter = new ViewPagerAdapter(getFragmentManager());
to
InteractionsFragment.ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());
That's fixed the issue

display textview as last item of list view

I want to display a textview as a last item of List View. Here is my xml code -
<LinearLayout
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"
android:orientation="vertical"
tools:context="com.activity.MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="8dp">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="60dp" />
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
</LinearLayout>
The list view will display card view one below other. However I want a textview as last item in the list.
For example, if i have 1 card view, I need to display textview below that.
If I have 2 card views, I need to display textview below the second card view.
How can I achieve this?
inflate your view like this.
LayoutInflater layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View root = layoutInflater.inflate(R.layout.yourLayout, null);
// for footerclick
//add code her root.setOnClickListner(...)
listView.addFooterView(root, null, true);
for click try this
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> listView, View view, final int position, long id) {
if(position < adapter.getCount()){
Log.d("test","working");
}
}
});
on Refresh listview
mListView.removeFooterView(root);
This can be solved by adding a footer to the list view.
It is very simple, just create a layout with the required Textview. Add it as a footer to the list view as below.
listView.addFooterView(footerView);
Please find more reference to adding footer from this Question.
You can wrap your ListView in LinearLayout and add TextView just below it. Then wrap that with NestedScrollView and set fillViewPort to true to still be able to scroll when TextView goes beyond screen
<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"
android:orientation="vertical"
tools:context="com.activity.MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="8dp">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="60dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Footer text view" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
</LinearLayout>

Strange behavior of the RecyclerView

I have the following code for example.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<String> names = new ArrayList<>();
names.add("one");
names.add("two");
names.add("three");
names.add("four");
names.add("five");
names.add("six");
names.add("seven");
names.add("eight");
names.add("nine");
names.add("ten");
RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
LinearLayoutManager llm = new LinearLayoutManager(this);
rv.setLayoutManager(llm);
RvAdapter adapter = new RvAdapter(names);
rv.setAdapter(adapter);
}
}
RvAdapter.java
public class RvAdapter extends RecyclerView.Adapter<RvAdapter.PersonViewHolder> {
public static final String TAG = RvAdapter.class.getSimpleName();
List<String> persons;
RvAdapter(List<String> persons) {
this.persons = persons;
}
#Override
public RvAdapter.PersonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new PersonViewHolder(v);
}
#Override
public void onBindViewHolder(RvAdapter.PersonViewHolder holder, int position) {
holder.name.setText(persons.get(position));
Log.d(TAG, "onBindViewHolder: " + position);
}
#Override
public int getItemCount() {
return persons.size();
}
public static class PersonViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView name;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.cv);
name = (TextView) itemView.findViewById(R.id.name);
}
}
}
activity_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.mrmayhem.myapplication.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
item.xml
<?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="wrap_content"
android:padding="16dp">
<android.support.v7.widget.CardView
android:id="#+id/cv"
android:layout_width="match_parent"
android:layout_height="200dp">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.v7.widget.CardView>
</LinearLayout>
It works so good and correct. When I scroll through the list I get successive messages from Adapter one by one in Logs: "onBindViewHolder: " + position. But my problem in next. When i try add some View above the RecyclerView, as shown in the code below. Adapter displays all calls of the method onBindViewHolder simultaneously. Wrap the RecyclerView in activity_main.xml by the next code.
activity_main.xml (with header)
<?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="com.example.mrmayhem.myapplication.MainActivity">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HEADER" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</RelativeLayout>
RecyclerView is a ListView. It will only display the items that you can currently see, reusing parts as you scroll.
Now you wrap the RecyclerView in a LinearLayout within a NestedScrollView, what happens?
A NestedScrollView needs to know the size of the LinearLayout to handle the scrolling.
How does the LinearLayout know how long it should be, without knowing the RecyclerViews total length? It doesn't.
So the recyclerView gets completely inflated, all views at once, all in a long line. No recycling, no reuse. This is the phenomenon you experience.
Now the LinearLayout can properly tell the NestedScrollView it's height (the total height of the TextView and all the items of the RecyclerView) and the NestedScrollView can handle the scrolling.
This is why nested scrolling is always a bad idea. If possible, try to move your TextView as an item into the RecyclerView and get rid of the wrapping NestedScrollview.
e.g. as seen here: Is there an addHeaderView equivalent for RecyclerView?
Another option would be to remove the recyclerview from the scroll view and put it below. The header would not scroll then, though.
Unless you have a good reason to have a NestedScrollView in your hierarchy, you could achieve a TextView on top with a RecyclerView below with just this layout code:
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical"
tools:context="com.example.mrmayhem.myapplication.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HEADER" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>

ListView only shows first item

I want to display all items of an ArrayList<String> on a ListView. I use an ArrayAdapter<String> for this. The problem is that only the first item ('foo' in my example) of the ArrayList is shown. Can someone tell me why? Am I missing something?
I've made an minimal example using the generated code (Tabbed Action Bar Spinner Activity) from Android Studio 2.
My FooActivity:
public class FooActivity extends AppCompatActivity {
...
public static class PlaceholderFragment extends Fragment {
private ListView fooListView;
private ArrayAdapter<String> mAdapter;
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_foo, container, false);
fooListView = (ListView) rootView.findViewById(R.id.foo_list);
updateList();
return rootView;
}
private void updateList() {
ArrayList<String> strings = new ArrayList<>();
strings.add("foo");
strings.add("bar");
if (mAdapter == null) {
mAdapter = new ArrayAdapter<>(getContext(),
R.layout.item_foo,
R.id.foo_string,
strings);
fooListView.setAdapter(mAdapter);
} else {
mAdapter.clear();
mAdapter.addAll(strings);
mAdapter.notifyDataSetChanged();
}
}
}
My fragment_foo.xml:
<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="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.foo.activities.FooActivity$PlaceholderFragment">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/foo_list"
android:layout_below="#+id/total_activities"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="10dp"
android:layout_alignParentBottom="true" />
</RelativeLayout>
And the item_foo.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
android:id="#+id/foo_string"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="some_string"
android:textSize="20sp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</LinearLayout>
If it helps I can post the generated activity_foo.xml (I didn't made any changes there) and the complete FooActivity class too.
The Problem actually was my activity_foo.xml which had a NestedScrollView. I've added android:fillViewport="true" and now it shows every item.
My NestedScrollView now looks like this:
<android.support.v4.widget.NestedScrollView
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fillViewport="true"/>
On any ListView, if you use android:layout_height="wrap_content", you're only going to see one item. Try android:layout_height="match_parent". If the ListView only takes up part of the layout, you'll need a LinearLayout with weights or a RelativeLayout with constraints. But wrap_content won't work for a height on a ListView, ever.
Your Listview look something like this
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/foo_list"
android:layout_marginTop="10dp"/>
I have removed from your list view android:layout_below="#+id/total_activities"
and
android:layout_alignParentBottom="true"
For others: It's okay to nest a ListView inside another layout, and it's also fine to use android:layout_height="wrap_content" on Layouts surrounding the ListView. (So long as the outer-most Layout allows for match_parent)
What is not fine, however, is when the TextView being used to populate the ListView is defined with layout_height="match_parent". It will cover up all of the subsequent rows after the first.
Bad:
<TextView
android:id="#+id/infoRow_textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Good:
<TextView
android:id="#+id/infoRow_textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

SwipeRefreshLayout - the RecyclerView is not pulled down

I have a RecyclerView with GridLayoutManager and when using SwipeRefreshLayout the RecyclerView is not pulled down. How to create the effect of having a gap between the toolbar and the recyclerview while refreshing?
XML:
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RecyclerView
android:id="#+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
CODE:
swipeLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_container);
swipeLayout.setOnRefreshListener(this);
swipeLayout.setColorScheme(android.R.color.holo_blue_bright, android.R.color.holo_green_light, android.R.color.holo_orange_light, android.R.color.holo_red_light);
gridView = (RecyclerView) getActivity().findViewById(R.id.gridView);
gridLayoutManager = new GridLayoutManager(getActivity(), 4, GridLayoutManager.VERTICAL, false);
gridView.setLayoutManager(gridLayoutManager);
gridView.setVisibility(View.GONE);
gridView.setHasFixedSize(false);
gridView.setItemAnimator(new DefaultItemAnimator());
Your code is all okay, but the swipeRefreshLayout does not pull down the grid view but only itself, For the demo check this video. You can however use other libraries like Ulta-Pull-to-Refresh to achieve the desired effect!

Categories