I have a LinearLayout xml with a RecyclerView:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:id="#+id/r1"
android:background="#DBDBDB">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DBDBDB" />
</LinearLayout>
In my java class I am setting the background image of whole Linearlayout:
LinearLayout linear;
linear = findViewById(R.id.r1);
linear.setBackgroundResource(R.drawable.visitedbg);
This is working fine. But I want to set background for the Linearlayout also in Recycleradapter.
In the list the user can remove any item by clicking on it. And if the last item is removed, I want to show a background image.
In onBindViewHoldermethod I have:
movieList.remove(position);notifyDataSetChanged();
if (getItemCount()<=0){holder.linear.setBackgroundResource(R.drawable.visitedbg);}
Problem is the Nullpointerexception, as I can't define the LinearLayout view in Recycleradapter.
I tried to put it to public MyviewHolder(View itemView), also in public RecyclerAdapter.MyviewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) as
LinearLayout linear = itemView.findViewById(R.id.r1);
but this is still not working. Is there any solution for this?
First of all, I recommend migrating from findViewById() to viewBindng to prevent app from crashing in running time.
Second, You can only access views inside recyclerView's items from adapter. to implement what you want, you should listen for recyclerView's adapter change. You can use AdapterDataObserver:
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
super.onItemRangeRemoved(positionStart, itemCount);
//...
}
});
Take a look at this link in android documentation.
Another way to achieve that will be checking for adapter's item count everytime you remove an element:
movieList.remove(position);
notifyItemRemoved(position);
if(adapter.getItemCount() == 0)
linear.setBackgroundResource(R.drawable.visitedbg)
Related
i am facing a problem i cannot resolve. i googled it but couldnt get the solution im looking for. i have a recycle view as follow:
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:paddingBottom="70dp"
android:layout_marginTop="#dimen/activity_vertical_margin"
this recycle view is showing in the screen as follow
if you notice, there is no spacing above the text and bottom of the text for each item. most likely due to wrap_content. i want to add space within the item cell on top and bottom. something like this image
if you noticed, i draw red arrows to indicate the extra space and the text in the center of each item list. how can i add space within the cell(space on top of text and space on bottom of text? left and right space will be cool too.
when i googled this, i only found code to add spacing between items. but what i am looking for is to add spacing within the cell item itself like the second picture attach. i would appreciate your help. thanks in advance
Definitely you are using an adapter for your recycler view and that adapter is responsible to create children. As #cocored said you have to create your own layout. you have to do it in your adapter (usually in onCreateViewHolder).
you can use inflater service to inflate an xml layout for each child.
recyclerview_child.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:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"/>
...
</LinearLayout>
and in your adapter do something like this
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
private List<Whatever> mData;
private LayoutInflater mInflater;
MyRecyclerViewAdapter(Context context, List<Whatever> data) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
}
// inflates the child layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_child, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each child
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Whatever obj = mData.get(position);
holder.myTextView.setText(obj.getName());
...
}
// total number of children
#Override
public int getItemCount() {
return mData.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder{
TextView myTextView;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.tv);
}
}
}
hope it helps
You would have to add a padding to your recycler item. If you're using a default item layout from android I would suggest creating your own layout.
I have construction where there are two items which are static and recyclerview with draggable items. Both types of view are wrapped by LinearLayout. LinearLayout is wrapped by NestedScrollView.
XML explanation:
<NestScrollView>
<LinearLayout>
<View></View>
<View></View>
<RecyclerView></RecyclerView>
</LinearLayout>
</NestScrollView>
Pic explanation:
Implementation of dragging items I took from this tutorial: https://medium.com/#ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.yc7me2ikf
The problem is the RecyclerView doesn't scroll when I drag his children out of screen. (However if I don't have NestedScrollView as a parent, RecyclerView works as expected.)
I searched every problem related to this but I didn't find any solution.
Putting recyclerView inside NestedScrollView is not a good practice. I recommend you to use your other views as RecyclerView items. I'm sure that will fix your problem as you've said "However if I don't have NestedScrollView as a parent, RecyclerView works as expected."
Make the NestedScrollView and RecyclerView play nice together by adding android:fillViewport="true" to the recycler
When you start to drag your item or once you reach the edge of the screen you can also turn off the recycler's nested behaviour with mRecyclerView.setNestedScrollingEnabled(false). This will cause the nested view itself to scroll so that the user continues down the recyclerview.
Once you're finished set nested scrolling to true again.
Alternatively you will need to look at delegating who gets the touch events like I outlined for another question here. For your sample it might be as simple as:
When drag starts call nestedScrollView.requestDisallowInterceptTouchEvent(true);
When drag ends requestDisallowInterceptTouchEvent(false) to reenable scrollview
If the requestDisallowInterceptTouchEvent fails to work, then you can create a subclass of NestedScrollView and override onInterceptTouchEvent like on my linked answer
I have faced the same problem. I use the other views as the recycler view.
First of all we have to return the two views in getItemViewType().
public int getItemViewType(int position)
{
if(position == 0)
{
return HEADERVIEW;
}
return LISTVIEW;
}
Now, we are adding the other view as the HeaderView in the list so we are going to tweak the list count:
#Override public int getItemCount()
{
return arrayList.size()+1;
}
Now bind the views correctly in onBindViewHolder on the basis on the getItemViewType()
#Override public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int i)
{
if(viewHolder.getItemViewType() == HEADERVIEW )
{
HeaderViewHolder headerViewHolder = (HeaderViewHolder)viewHolder;
headerViewHolder.headertextview.SetText("LongText");
}
else
{
MyHolder myHolder = (MyHolder) viewHolder;
myHolder.name.setText(arrayList.get(i-1).name);
}
Now in the Item Touch Listener Callback we have to tweak the onMove() method:
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// get the viewHolder's and target's positions in your adapter data, swap them
if(viewHolder.getItemViewType() != target.getItemViewType())
{
return false;
}
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
if(dragFrom == -1)
{
dragFrom = fromPosition;
}
dragTo = toPosition;
if(dragFrom != -1 && dragTo != -1 && dragFrom != dragTo)
{
reallyMoved(dragFrom, dragTo);
dragFrom = dragTo = -1;
}
// and notify the adapter that its dataset has changed
adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
Now if all the logic is right then we move the item and call onreallyMoved() method:
private void reallyMoved(int dragFrom, int dragTo)
{
if(dragFrom == 0 || dragTo == arrayList.size())
{
return;
}
Collections.swap(arrayList, dragFrom-1, dragTo-1);
}
If you want to know more have a look at my blog post.
Another solution is to use a linearLayout instead the NestedScrollView. At its root, put the recyclerView, with parameter : sethasFixedSize(true) in your Java file, and with match_parent height as well in xml.
recap :
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RecyclerView
...
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
don't forget to set recyclerView.setHasFixedSize(true); in your Java file
Go with something like:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v4.widget.NestedScrollView
android:id="#+id/view_noRecord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:id="#+id/tv_no_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginBottom="#dimen/_20sdp"
android:gravity="center_horizontal"
android:padding="#dimen/_10sdp"
android:text="#string/no_data_found"
android:visibility="gone"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.v4.widget.NestedScrollView>
<android.support.v7.widget.RecyclerView
android:id="#+id/common_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadeScrollbars="true"
android:scrollbars="vertical"
android:visibility="gone"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</FrameLayout>
Or try to this put content from your layout as a header of your RecyclerView
<LinearLayout>
<View></View>
<View></View>
</LinearLayout>
I have two RecylerViews in a LinearLayout with vertical orientation inside a ScrollView. Both RecyclerViews want to display a list of 6 strings in TextViews. The arrangement is such that at the start, the TextViews of just the first RecyclerView show up and upon scrolling, those of the second RecyclerView show up.
My expectation is that since none of the TextViews of the second RecyclerView is visible, they won't be created, and once they come in view, the onBindViewHolder will be called to reuse existing ViewHolders. However, all of the individual ViewHolders are created (onCreateView called). Am I doing something wrong? Because if this is expected, there is no point of setting a common ViewPool, is there?
Activity Code
public class MainActivity extends AppCompatActivity {
private List<String> names = Arrays.asList(
"Name 1", "Name 2", "Name 3", "Name 4", "Name 5", "Name 6"
);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
RecyclerView recycler1 = (RecyclerView) findViewById(R.id.recycler1);
RecyclerView recycler2 = (RecyclerView) findViewById(R.id.recycler2);
recycler1.setLayoutManager(new LinearLayoutManager(this));
recycler2.setLayoutManager(new LinearLayoutManager(this));
recycler1.setRecycledViewPool(viewPool);
recycler2.setRecycledViewPool(viewPool);
recycler1.setNestedScrollingEnabled(false);
recycler2.setNestedScrollingEnabled(false);
recycler1.setAdapter(new SampleAdapter(new ArrayList<>(names), 1));
recycler2.setAdapter(new SampleAdapter(new ArrayList<>(names), 2));
}
private class SampleAdapter extends RecyclerView.Adapter {
private final List<String> mSampleList;
private final int mRecyclerId;
SampleAdapter(List<String> sampleList, int recyclerId) {
mSampleList = sampleList;
mRecyclerId = recyclerId;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.i("TESTING", "creating a new view for parent Id: " + mRecyclerId);
TextView textView = (TextView) getLayoutInflater().inflate(R.layout.text_view_name, null);
return new SampleViewHolder(textView);
}
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Log.i("TESTING", "binding existing view for parent Id: " + mRecyclerId + " for position: " +
position);
((SampleViewHolder)holder).bind(mSampleList.get(position));
}
public int getItemCount() {
return mSampleList.size();
}
}
private class SampleViewHolder extends RecyclerView.ViewHolder {
private TextView mText;
public SampleViewHolder(TextView itemView) {
super(itemView);
mText = itemView;
}
public void bind(String s) {
mText.setText(s);
}
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scroll_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/recycler_containers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorAccent"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"/>
</LinearLayout>
</ScrollView>
TextView
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/name_text_view"
android:layout_width="match_parent"
android:layout_height="400dp"
android:paddingTop="40dp"
android:paddingRight="40dp"
android:paddingBottom="40dp"
android:paddingLeft="40dp"
android:textColor="#color/white"
android:gravity="center">
</TextView>
First off, using RecyclerView inside a ScrollView is never a good idea. A ScrollView will layout its child, in your case a LinearLayout, which will also layout its children: The 2 RecyclerViews.
I will start from bottom up: Both RecyclerView get to be as tall as their parent, or less, since they are told to wrap_content. They both get layouted, and are within the LinearLayout, which will have the height of both RecyclerViews. In case the LinearLayout is bigger than the screen, the ScrollView will make everything scrollable. You now have a tall layout that shows the full content and is scrollable.
Things to notice: A scrollview does not recycle any views. If a view is off screen it might not get drawn, but the view itself does not "act" upon this information, for all the view knows it is currently displayed to the user. Basically both RecyclerViews are properly layouted to their full height within the LinearLayout, which will stretch to the height needed. Al the RecyclerViews know is that they are visible—and need to have all their children bound. This is your "problem".
there is no point of setting a common ViewPool, is there?
Since both RecyclerViews are "visible" there is no recycling and no reuse. A RecyclerView that doesn't scroll because it is inside a ScrollView will not recycle its views. You are correct, there is no recycling going on, and the shared ViewPool is useless.
With the layout you describe you should get rid of the ScrollView altogether and use a single RecyclerView to properly scroll and recycle the views. Whatever you need the ScrollView for, you can accomplish the same with a RecyclerView. ScrollView is for static layouts, RecyclerView for lists.
Shared ViewPools are intended to be used if you have multiple Fragments or things like ViewPagers, where you have a lot of the same Views over different screens.
I have a recyclerview inside SwipeRefreshLayout. and at the end of recyclerview, I'd like to add a button, but I'm unable to do so. Here the code :
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/refresh"
android:layout_width="wrap_content"
android:layout_below="#+id/toolbar"
android:paddingBottom="50dp"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"/>
<Button
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="#+id/load_more"
android:layout_alignParentBottom="true"
android:textColor="#color/md_black_1000"
android:text="TEST"/>
</android.support.v4.widget.SwipeRefreshLayout>
The button does not appear at the end of the recyclerview.
SwipeRefreshLayout could have only one child.
Add RecyclerView and Button to vertical LinearLayout and put it into SwipeRefreshLayout.
<android.support.v4.widget.SwipeRefreshLayout>
<LinearLayout>
<android.support.v7.widget.RecyclerView>
<Button>
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
To add Button as last item in RecyclerView you need edit adapter:
1) increase number of rows
#Override
public int getItemCount() {
return pictureArrayList.size() + 1;
}
2) show Button when list ends
#Override
public void onBindViewHolder(final ExampleHolder holder, final int position) {
final Picture picture = pictureArrayList.get(position);
if (position <= pictureArrayList.size()) {
holder.title.setVisibility(View.VISIBLE);
holder.button.setVisibility(View.GONE);
holder.title.setText(picture.getName());
holder.imageView.setImageResource(picture.getImage());
} else {
holder.title.setVisibility(View.GONE);
holder.button.setVisibility(View.VISIBLE);
}
}
You need to create a RecyclerView with different view items depending on what you want to do may be an option to use a view button at the bottom of the list, I have a blog post where I wrote a blog about the RecyclerView(Spanish).
http://erikcaffrey.github.io/2015/10/05/recyclerview/
You can see the code!
https://github.com/erikcaffrey/RecyclerView-Examples
Hi i use horizontal RecyclerView. But except horizontal devider i need vertical devider in each Item (different height).
I try
<View
android:layout_width="3dp"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"/>
This work then i set android:layout_height="50dp". But with android:layout_height="wrap_content" View it's gone.
I try get height from adapter
#Override
public void onBindViewHolder(final ClubListViewHolder holder, final int position) {
holder.parent.getHeight();
}
Method return -1
How solve this trouble?
You can use android:layout_height="match_parent" instead, place the view in ViewHolder layout. Then its height will be the same as item's height.