I am coming from a web development background (PHP). In my example, I retrieve a list of users, with their profile image, first and last name. Now I want each row of data (which represents a user), to open an activity to that clicked user profile.
On the web, it was simple by adding links with PHP. But how do I do that with Java and Android?
Right now, I managed to create a simple list that is fetched as a String array with simple text. But it's not clickable.
This is my current code: (I didn't include the XML files code, I don't think it's relevant)
**For test purpose, you see I use an array of Strings with 15 rows of data, and each String is acting as "first name" and "last name" - again, just for testings.
I want to know how to make those lines of data clickable and send to a new activity with the user's details. (If I can "mimic" data that will be sent to that new activity that would be great!)
MainActivity.java:
package com.example.recycleview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
String[] myDataset = new String[16];
myDataset[0] = "Data0";
myDataset[1] = "Data1";
myDataset[2] = "Data2";
myDataset[3] = "Data3";
myDataset[4] = "Data4";
myDataset[5] = "Data5";
myDataset[6] = "Data6";
myDataset[7] = "Data7";
myDataset[8] = "Data8";
myDataset[9] = "Data9";
myDataset[10] = "Data10";
myDataset[11] = "Data11";
myDataset[12] = "Data12";
myDataset[13] = "Data13";
myDataset[14] = "Data14";
myDataset[15] = "Data15";
// specify an adapter (see also next example)
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
}
}
MyAdapter.java:
package com.example.recycleviewe;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.w3c.dom.Text;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private String[] mDataset;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class MyViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView upTv;
public TextView downTv;
public View layout;
public MyViewHolder(View v) {
super(v);
layout = v;
upTv = (TextView)v.findViewById(R.id.upTv);
downTv = (TextView)v.findViewById(R.id.downTv);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.upTv.setText(mDataset[position]);
holder.downTv.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.length;
}
}
Android has this concept of intent. It is used to start activities as well as passing messages between components.
In your onBindViewHolder add:
holder.layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), Main2Activity.class);
intent.putExtra("fname", mDataset[position]);
intent.putExtra("lname", mDataset[position]);
v.getContext().startActivity(intent);
}
});
cheers!
Related
theList.add(data.getString(0));
theList.add(data.getString(1));
theList.add(data.getString(2));
theList.add(data.getString(3));
theList.add(data.getString(4));
I want to add all these indexes as a single row
I have Tried follwing code but it didn`t worked
theList.add(data.getString(0),data.getString(1),data.getString(2),data.getString(3),data.getString(4));
This is the Full Code of my Class. What i am trying to do is take data from my sqlite database and show in list view.
By this following code i am getting values in different rows but i want them in a single row
package com.example.project;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Mitch on 2016-05-13.
*/
public class ViewListContents extends AppCompatActivity {
DBHelper myDB;
User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewlistcontents_layout);
ListView listView = (ListView) findViewById(R.id.listView);
myDB = new DBHelper(this);
//populate an ArrayList<String> from the database and then view it
ArrayList<String> theList = new ArrayList<>();
Cursor data = myDB.viewbuses();
if(data.getCount() == 0){
Toast.makeText(this, "There are no contents in this list!",Toast.LENGTH_LONG).show();
}else{
while(data.moveToNext()) {
theList.add(data.getString(0));
theList.add(data.getString(1));
theList.add(data.getString(2));
theList.add(data.getString(3));
theList.add(data.getString(4));
theList.add("");
ListAdapter listAdapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,theList);
listView.setAdapter(listAdapter);
}
}
}
}
Thanks in Advance
This is How I Resolved It
First of All Thanks to Mr. Zain He Helped me to get it done.
I Concatenated Strings and it worked.
I wanted to Give space Between Values so this is how I did it.
theList.add(data.getString(0)+" "+data.getString(1)+" "
+data.getString(2)+" " +data.getString(3)+" "+data.getString(4));
A Good Practice is to add .Concat() instead of "+"
Thank You!
I recommend using RecyclerView instead because it provides far more functionality than ListView. It also leads to better performance. You will have to extend RecyclerView.Adapter and RecyclerView.ViewHolder as shown below.
MyAdapter is similar to ArrayAdapter. It connects the RecyclerView to our data.
MyDataViewHolder stores all the views for a single item in the list. In our case that is a single TextView, but it could be more.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyDataViewHolder> {
private List<String> mList;
public MyAdapter(List<String> list){
this.mList = list;
}
protected static class MyDataViewHolder extends RecyclerView.ViewHolder{
protected TextView viewData;
public MyDataViewHolder(View itemView) {
super(itemView);
viewData = (TextView) itemView.findViewById(R.id.data);
}
}
}
You will also have to implement the following methods inside MyAdapter.
onCreateViewHolder creates a MyDataViewHolder from xml.
onBindViewHolder populates the MyDataViewHolder using our data.
returns the number of elements shown.
#Override
public MyDataViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.my_data, viewGroup, false);
return new MyDataViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyDataViewHolder viewHolder, int i) {
String string = mList.get(i);
viewHolder.viewData.setText(person.getLastName());
}
#Override
public int getItemCount() {
return mList.size();
}
Now use this inside your onCreate function.
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), numberOfColumns));
mAdapter = new MyAdapter(mList);
mRecyclerView.setAdapter(mAdapter);
I have already seen a lot of material on this subject even here, namely the list of individual elements of the list. My application receives from the server two lists of messages, incoming and outgoing. And when you click on one of these two lists, you need to switch to the activation, which contains the selected message. When you press it, you need to somehow pull it out the way we said and throw this id into the query. I currently have such an adapter for RecyclerView:
package com.example.developer_4.test_login.Tabs;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.developer_4.test_login.R;
import com.example.developer_4.test_login.data.model.Message;
import java.util.List;
class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.ViewHolder> {
private RecyclerView recyclerViewItemClickListener;
private List<Message> messageList;
private Context ctx;
MessageAdapter(List<Message> messageList, Context ctx) {
this.messageList = messageList;
this.ctx = ctx;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_of_rec_m, viewGroup, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Message message = messageList.get(position);
String id = String.valueOf(message.getId());
holder.subject.setText(message.getSubject());
holder.from.setText(message.getSender_name());
holder.date.setText(message.getDate());
holder.getAdapterPosition();
}
#Override
public int getItemCount() {
return messageList.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
final TextView from, subject, date;
int position = 0;
ViewHolder(View v) {
super(v);
subject = v.findViewById(R.id.subject);
from = v.findViewById(R.id.from);
date = v.findViewById(R.id.date);
//id = v.findViewById(R.id.id);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
}
}
at the moment I have hung on a click on the message element sending a request with the id of the message that I entered manually, I have a function getId in the response class from the server, that is, I can get this id, but I do not understand how to catch clicking on a separate list item . I've seen ways to use position but I somehow did not get accustomed to them)) after clicking on a certain element of this list, I need to pass on to another activity of the id of the message by which we clicked in the list, in order to display this message on the other screen.
Thank you all for valuable advice, answers and criticism)). Thank you in advance for your cooperation.
Just try setting :
holder.setTag(position);
then
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int pos = (int)view.getTag();
Message message = messageList.get(pos);
}
});
You can add data by adding tag to any view in your onBindViewHolder method.
holder.itemView.setTag("Some Data");
And then get that tag when clicked.
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String someData=(String)view.getTag();
}
});
I need to show a 4x10 grid of random colors. The grid should fill the screen horizontally and vertically, and all cells should be of equal dimensions. Since the grid (4x10) dimensions can change in the future, GridLayout made more sense to me than TableLayout. GridView and RecyclerView are out because I don't need any scrolling behavior.
Since I need to add these child views at runtime, I started with calculating cell width and height as a ration of screen width and height. Then I stumbled across this SO post which says GridLayout has better ways to achieve such behavior. There is a code example for static (XML) based views, but I am not able to find a Java/Kotlin example. I am experimenting with GridLayout.Spec to use in the LayoutParams for the child views, but can't figure out how it works.
Updated with a screenshot of desired layout. This image is 12x10, but I want the flexibility to change the dimensions (compile time).
Similar to LinearLayout, there is a weight attribute in GridLayout spec - which you can set to 1 for all views. Similar to LinearLayout, make the width and height 0 using weights. Use Undefined as position as you want to draw the views in sequence, else pass the corresponding position for each cell.
gridLayout.rowCount = rowCount
gridLayout.columnCount = colCount
for (i in 1..rowCount*colCount){
val layoutParams: GridLayout.LayoutParams = GridLayout.LayoutParams(
GridLayout.spec(GridLayout.UNDEFINED, 1f),
GridLayout.spec(GridLayout.UNDEFINED, 1f)).apply {
width = 0
height = 0
}
val blueView = View(this).apply {
setBackgroundColor(Color.BLUE)
}
gridLayout.addView(blueView, layoutParams)
}
If you want to generate grid layout col and row dynamically you can use grid layout with recycler view.
1. xml code
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
/>
</android.support.v4.widget.SwipeRefreshLayout>
2 create a model classs as per your requriement
public class AllAssignedTableModel {
#SerializedName("table_id")
private int table_id;
#SerializedName("table_name")
private String table_name;
#SerializedName("restaurant_id")
private int restaurant_id;
#SerializedName("waiter_id")
private int waiter_id;
#SerializedName("image")
private String image;
#SerializedName("table_status")
private int table_status;
#SerializedName("table_bill")
private double table_bill;
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public int getTable_id() {
return table_id;
}
public void setTable_id(int table_id) {
this.table_id = table_id;
}
public String getTable_name() {
return table_name;
}
public void setTable_name(String table_name) {
this.table_name = table_name;
}
public int getRestaurant_id() {
return restaurant_id;
}
public void setRestaurant_id(int restaurant_id) {
this.restaurant_id = restaurant_id;
}
public int getWaiter_id() {
return waiter_id;
}
public void setWaiter_id(int waiter_id) {
this.waiter_id = waiter_id;
}
public int getTable_status() {
return table_status;
}
public void setTable_status(int table_status) {
this.table_status = table_status;
}
public double getTable_bill() {
return table_bill;
}
public void setTable_bill(double table_bill) {
this.table_bill = table_bill;
}
}
3. create adapter of recycler view as per your requirement.
package talent4assure.com.manageyourrestaurant.adapter;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.gson.Gson;
import java.util.HashMap;
import java.util.List;
import talent4assure.com.manageyourrestaurant.R;
import talent4assure.com.manageyourrestaurant.model.AllAssignedTableModel;
import static android.content.Context.MODE_PRIVATE;
public class WaAssignedTableListAdapter extends RecyclerView.Adapter<WaAssignedTableListAdapter.EmployeeViewHolder> {
private Context context;
private List<AllAssignedTableModel> dataList;
// public ImageView img;
public static final String MY_BILL_PREFS = "MyBillPrefsFile";
String tableId,billAmount;
HashMap<String, String> billMap=new HashMap<String, String>();
public WaAssignedTableListAdapter(List<AllAssignedTableModel> dataList, Context context) {
this.dataList = dataList;
this.context=context;
}
#Override
public EmployeeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.waiter_cards_layout, parent, false);
return new EmployeeViewHolder(view);
}
#Override
public void onBindViewHolder(EmployeeViewHolder holder, int position) {
holder.tvAssignTableName.setText(dataList.get(position).getTable_name());
holder.tvCustomerBill.setText(String.valueOf(dataList.get(position).getTable_bill()));
int status = dataList.get(position).getTable_status();
if(status == 1){
holder.llBackground.setBackgroundResource(R.drawable.llred_background);
}else {
holder.llBackground.setBackgroundResource(R.drawable.llblue_background);
}
}
#Override
public int getItemCount() {
return dataList.size();
}
class EmployeeViewHolder extends RecyclerView.ViewHolder {
TextView tvAssignTableName,tvCustomerBill;
LinearLayout llBackground;
EmployeeViewHolder(View itemView) {
super(itemView);
tvAssignTableName = (TextView) itemView.findViewById(R.id.tvAssignTableName);
tvCustomerBill = (TextView)itemView.findViewById(R.id.tvCustomerBill);
llBackground = (LinearLayout)itemView.findViewById(R.id.llBackground);
}
}
}
4. java class activity code
no of column u can pass statically or you can pass val dynamically as per your requirement(in this example i am taking it as 4). and no of row will get created as per your data dynamically. hope it will help you.
private WaAssignedTableListAdapter adapter;
private RecyclerView recyclerView;
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());
adapter = new WaAssignedTableListAdapter(allAssignedTableModels, WaiterActivity.this);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getApplicationContext(), 4, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
How to infinite scroll load more with Recycleview
how can i display result like infinite means when user scroll dynamic data automatically fetch and show. so loading time consume and application will work fine.
File Name: MainActivity.java //Main Java file that i want to show load more
package com.ejobbox.ejobbox;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ProgressBar progressBar;
private LinearLayoutManager mLayoutManager;
private RecyclerViewAdapter adapter;
private ArrayList<Model> list;
private String baseURL="http://mywebsite.com/";
public static List<WPPost> mListPost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView= findViewById(R.id.recycler_view);
progressBar=findViewById(R.id.progressbar);
mLayoutManager=new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(mLayoutManager);
list=new ArrayList<Model>();
// call retrofit
getRetrofit();
adapter=new RecyclerViewAdapter(list,MainActivity.this);
recyclerView.setAdapter(adapter);
}
private void getRetrofit(){
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitArrayApi service = retrofit.create(RetrofitArrayApi.class);
Call<List<WPPost>> call= service.getPostInfo();
call.enqueue(new Callback<List<WPPost>>() {
#Override
public void onResponse(Call<List<WPPost>> call, Response<List<WPPost>> response) {
Log.e("mainactivty","response"+ response.body());
progressBar.setVisibility(View.GONE);
for(int i=0; i<response.body().size();i++){
Log.e ("main","Title"+ response.body().get(i).getTitle().getRendered()+" "+
response.body().get(i).getId());
String tempdetails=response.body().get(i).getExcerpt().getRendered().toString();
tempdetails=tempdetails.replace("<p>","");
tempdetails=tempdetails.replace("</p>","");
String linkdetail=response.body().get(i).getLink().toString();
String date=response.body().get(i).getDate().toString();
list.add(new Model(Model.IMAGE_TYPE, response.body().get(i).getTitle().getRendered(),
tempdetails,date,
response.body().get(i).getLinks().getWpFeaturedmedia().get(0).getHref(),linkdetail) );
}
adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<List<WPPost>> call, Throwable t) {
}
});
}
}
(This is RecyclearViewAdapter that i have define recyclear view Adapter.)
File Name: RecyclearViewAdapter.java //Recyclear View Adapter File
package com.ejobbox.ejobbox;
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class RecyclerViewAdapter extends RecyclerView.Adapter{
private ArrayList<Model> dataset;
private Context mContext;
public RecyclerViewAdapter(ArrayList<Model> mlist, Context context) {
this.dataset=mlist;
this.mContext=context;
}
public static class ImageTypeViewHolder extends RecyclerView.ViewHolder{
TextView title,subtitle,link,date;
ImageView imageView;
public ImageTypeViewHolder(View itemView){
super(itemView);
this.title=(TextView)itemView.findViewById(R.id.title);
this.link=(TextView)itemView.findViewById(R.id.link);
this.subtitle=(TextView) itemView.findViewById(R.id.subtitle);
this.imageView=(ImageView) itemView.findViewById(R.id.icon);
this.date=(TextView)itemView.findViewById(R.id.date);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.postdetails,parent,false);
return new ImageTypeViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final Model object=dataset.get(position);
((ImageTypeViewHolder) holder).title.setText(object.title);
((ImageTypeViewHolder) holder).subtitle.setText(object.subtitle);
//((ImageTypeViewHolder) holder).link.setText(object.link);
((ImageTypeViewHolder) holder).date.setText((CharSequence) object.date);
((ImageTypeViewHolder) holder).title.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent(mContext, WPPostDetails.class);
intent.putExtra("itemPosition",position);
intent.putExtra("link",object.link.toString());
mContext.startActivity(intent);
}
});
}
#Override
public int getItemCount() { return dataset.size();}
}
Do not use infinite scroll it does not work as expected.
You can use this
recyclerView.addOnScrollListener(new OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (isLastItemDisplaying())
{
scrollCount=scrollCount+10;
L.v("scroll count",""+recyclerView.getAdapter().getItemCount());
loadMoreItems(scrollCount);
}
}
});
private boolean isLastItemDisplaying()
{
if (storiesList.getAdapter().getItemCount()!=0) {
int last_visible_count=manager.findFirstCompletelyVisibleItemPosition();
if (last_visible_count!=RecyclerView.NO_POSITION && last_visible_count==storiesList.getAdapter().getItemCount()-1) {
return true;
}
}
return false;
}
Inside this loadMoreItems method call your api. Make sure to send this scroll count to your server on each api call .And in sql query you have to do this
EX:
For example on first time your count is 0;
SELECT * FROM posts LIMIT 0,10
On Scroll your scrollCount value will get increased by 10 (you can use your value scroll count values will fetch next 10 rows)
SELECT * FROM posts LIMIT 10,10
You only have to add your new data to the last position of list movies and everything will work fine. For this-
Create a new List of List<Model> newList and add your updated data to it. Now add newList into list and notify to adapter. Just like below-
List<Model> newList = new ArrayList<>();
// your code..
recyclerView.addOnScrollListener(new EndlessScrollListener(mLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
loadingMore=true;
getRetrofit();
int currentSize = adapter.getItemCount();
list.addAll(newList);
adapter.notifyItemRangeInserted(currentSize, list.size() - 2);
}
});
And here you can find the EndlessScrollListener class.
please look at my other related answers to more details-
How to load more items in a ListView using AsyncTask or any other method
Continious scrolling in recyclerview by Json request and adding new item with previous
Hope it will help.
Here is example for Simple Implementation of Endless Scrolling RecyclerView using a Simple Library compiled from the various sources.
Add this line in build.gradle
implementation 'com.hereshem.lib:awesomelib:2.0.1'
Create RecyclerView Layout in Activity with
<com.hereshem.lib.recycler.MyRecyclerView
android:id="#+id/recycler"
app:layoutManager="LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Create a ViewHolder by passing the class that supports
public static class EVHolder extends MyViewHolder<Events> {
TextView date, title, summary;
public EVHolder(View v) {
super(v);
date = v.findViewById(R.id.date);
title = v.findViewById(R.id.title);
summary = v.findViewById(R.id.summary);
}
#Override
public void bindView(Events c) {
date.setText(c.date);
title.setText(c.title);
summary.setText(c.summary);
}
}
Create Items List variable and adapters with very few lines by passing items, class and layout in the adapter
List<Events> items = new ArrayList<>();
MyRecyclerView recycler = findViewById(R.id.recycler);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, items, EVHolder.class, R.layout.row_event);
recycler.setAdapter(adapter);
ClickListener and LoadMore Listener can be added with following lines
recycler.setOnItemClickListener(new MyRecyclerView.OnItemClickListener() {
#Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, "Recycler Item Clicked " + position, Toast.LENGTH_SHORT).show();
}
});
recycler.setOnLoadMoreListener(new MyRecyclerView.OnLoadMoreListener() {
#Override
public void onLoadMore() {
loadData();
}
});
loadData();
After the data is loaded this must be called
recycler.loadComplete();
When no LoadMore is required LoadMore layout can be hidden by calling
recycler.hideLoadMore();
More example can be found here
Hope this helps :)
I have created a very simple project, displaying 28 images with StaggeredGridLayoutManager by recyclerview. but as I scroll the recyclerview it moves items for example from left to right or swap the column of left and right.
codes:
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
public class MainActivity extends Activity {
String mImageDir;
private RecyclerView mRecyclerView;
private StaggeredGridLayoutManager mLayoutManager;
MyRecyclerAdapter myRecyclerAdapter;
List<ImageModel> mImageList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview_rootview);
mLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
mLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(false);
mImageList = new ArrayList<ImageModel>();
for (int i = 1; i < 29 ; i++) {
ImageModel img = new ImageModel();
img.setTitle("Image No " + i);
int drawableResourceId = this.getResources().getIdentifier("image"+String.valueOf(i), "drawable", this.getPackageName());
img.setResId(drawableResourceId);
mImageList.add(img);
}
myRecyclerAdapter = new MyRecyclerAdapter(MainActivity.this,mImageList);
mRecyclerView.setAdapter(myRecyclerAdapter);
}
}
And the adapter:
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
private List<ImageModel> mItems;
Context mContext;
public MyRecyclerAdapter(Context context,List<ImageModel> objects) {
mContext = context;
mItems = objects;
}
static class ViewHolder extends RecyclerView.ViewHolder{
public ImageView mImageView;
public TextView mTextView;
public View rootView;
public ViewHolder(View itemView) {
super(itemView);
rootView = itemView;
mImageView =(ImageView)itemView.findViewById(R.id.image);
mTextView =(TextView)itemView.findViewById(R.id.title);
}
}
#Override
public int getItemCount() {
return mItems.size();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ImageModel item = mItems.get(position);
Picasso.with(mContext).load(item.getResId()).into(holder.mImageView);
holder.mTextView.setText(item.getTitle());
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
LayoutInflater inflater =
(LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View convertView = inflater.inflate(R.layout.item, parent, false);
return new ViewHolder(convertView);
}
}
and a sample moving item:
http://i.imgur.com/FUapm2K.gif?1
if you play (scroll up and down) you can discover more interesting animation :-)
How to prevent that and having stable layout like an ordinary listview?
Edit
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ImageModel item = mItems.get(position);
RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams)holder.mImageView.getLayoutParams();
float ratio = item.getHeight()/item.getWidth();
rlp.height = (int)(rlp.width * ratio);
holder.mImageView.setLayoutParams(rlp);
Picasso.with(mContext).load(item.getResId()).into(holder.mImageView);
holder.mTextView.setText(item.getTitle());
}
This is happening because SGLM does not keep any w/h information about the views. So each time a View is rebound, it gets the place holder size first and then the final size when the image is loaded.
Loading the actual image w/ different size (than place holder) triggers a new layout request, and during that layout request, SGLM detects that there will be gaps in the UI (or some item w/ higher position appears below an item w/ lower position) thus re-orders items w/ an animation.
You can avoid it by setting your place holder image to the dimensions of the actual image. If you don't have it ahead of time, you can save them after the image is loaded for the first-time and use it in the next onBind call.
What worked for me was to disable all animation on the recycle view when using StaggeredGridLayoutManager.
mRecyclerView.setItemAnimator(null);
You can create your own animator if you only want to restrict moving animations and keep the add and remove item animations.
You can try this
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL);
manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
mRecyclerView.setLayoutManager(manager);
after you set this, you'll find there is a blank at the top when you scroll to the top. continue to set this
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
((StaggeredGridLayoutManager)recyclerView.getLayoutManager()).invalidateSpanAssignments();
}
});
It's work for me, I get this way somewhere. I hope it can help you!
Change this line
mLayoutManager.setGapStrategy(
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
to this line
mLayoutManager.setGapStrategy(
StaggeredGridLayoutManager.GAP_HANDLING_NONE);
Add the following line at the end of the method:
holder.mImageView.requestLayout();
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
...
holder.mImageView.requestLayout();
}
This fixed the issue for me.
Maybe this is a more efficient way:
mBrandRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if(newState == RecyclerView.SCROLL_STATE_IDLE){
mBrandRecyclerView.invalidateItemDecorations();
}
}
});
For more information:
https://github.com/ibosong/CommonItemDecoration
Set your recyclerview's height fixed and item height and width wrap-content for staggered-layout-manager
First set gap strategy like following code :
mLayoutManager = new StaggeredGridLayoutManager(SPAN_COUNT, StaggeredGridLayoutManager.VERTICAL);
mLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
and then add your item to mItems and then use:
mAdapter.notifyItemInserted(mItems.size() - 1);
this method is better than using:
mAdapter.notifyDataSetChanged();