Adding equally sized views dynamically in GridLayout - android

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);

Related

how can i apply limit to recyclerview?

i want apply limit to recyclerview and only show 5 result in it and in the end of the list show a button for go to another place?!
my code in below;
adapter codes:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.Holder> {
ArrayList<Products> ProductsList;
Context context;
public ProductAdapter(ArrayList<Products> productsList, Context context) {
ProductsList = productsList;
this.context = context;
}
#NonNull
#Override
public Holder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.row_layout_horizental, parent, false);
return new Holder(v);
}
#Override
public void onBindViewHolder(#NonNull Holder holder, int position) {
Products products = ProductsList.get(position);
holder.txtName.setText(products.getName());
holder.txtPrice.setText(products.getPrice());
Picasso.get().load(Config.ip_value + "/images/" + products.getPhoto()).into(holder.imgV);
}
#Override
public int getItemCount() {
return ProductsList.size();
}
public class Holder extends RecyclerView.ViewHolder {
TextView txtName;
TextView txtPrice;
ImageView imgV;
public Holder(#NonNull View itemView) {
super(itemView);
txtName = itemView.findViewById(R.id.rowTxtProductName);
txtPrice = itemView.findViewById(R.id.rowTxtPrice);
imgV = itemView.findViewById(R.id.rowImgProduct);
}
}
}
i have some codes in main fragment but i dont think its necessary to put in this place but if you want to see them comment and i will put all in update text
thanks
You can either slice the list to contain only 5 items before passing it to RecyclerView or just change getItemCount method in Adapter to return 5
#Override
public int getItemCount() {
return ProductsList.size() > 5 ? 5 : ProductsList.size();
}
You can set limit as by using getItemCount() as
#Override
public int getItemCount() {
return 5;
}
by another place if u mean to other activity or fragment, then place
the button at the end of your recyclerview layout in your xml file.
for e.g : if using RelativeLayout,
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:id="#+id/recyclerview"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Next"
android:layout_alignParentBottom="true"
android:layout_below="#+id/recyclerview"
android:id="#+id/btn_next"/>
</RelativeLayout>
then on button click you can call the intent or similar to go to your page
You can set limit query in your ProductsList API.
if you are using retrofit2
you can define limit parametr in your API interface, if that option has in your backend server,
#GET("products")
Call<Products> getProducts(#Query("limit") int limit);
and define method in your activity class where you pass setAdapter, like below
public void getProducts(int limit){
Call<Products> call = yourAPI.getProducts(limit);
call.enqueue(new Callback<Products>() {
#Override
public void onResponse(Call<Products> call, Response<Products> response) {
if (response.isSuccessful() && response.body() != null) {
ArrayList<Products> products = response.body();
if (products == null) products = new ArrayList<>();
productsAdapter.setData(products); // setData needs to be defined in your adapter
} else {
Toast.makeText(yourActivity.this, "Server Error", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<Products> call, Throwable t) {
if(t.getMessage() != null) Log.e("ErrorTag", t.getMessage());
Toast.makeText(yourActivity.this, "Server Error", Toast.LENGTH_SHORT).show();
}
});
Don't forget to define new method called setData,
public void setData(ArrayList<Products> productsList) {
this.ProductsList.addAll(productsList);
notifyDataSetChanged();
};
And to get other 5 products I don't advise you to create next or prev button,
better add code below in your onBindViewHolder method of your adapter to make load another 5 more products when user scrolls to the last item,
if (position == (ProductsList.size() - 1)){
if (context instanceof YourActivity){
YourActivity activity = (YourActivity) context;
activity.getProducts(ProductsList.size());
}
}

How to set OnclickListener for the dynamically added items in recyclerview?

In my application I'm using a recycler view to show some data and for each item in recyclerview I'm adding a list of checked text view. These checked textviews are added according to the size of list provided and it works fine. Now I want to add the click listener for those items to know if they are checked or not?
When items are checked those checked items should be taken to another activity. But now the click listener is added directly in recycler view which won't access me to do out of box code. So I'm looking for how to add a click listener and access it in another activity.
My Recyclerview code:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.allio.customer.R;
import com.allio.customer.models.Types_Item;
import com.bumptech.glide.Glide;
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.github.florent37.expansionpanel.ExpansionLayout;
import com.github.florent37.expansionpanel.viewgroup.ExpansionLayoutCollection;
public class Types_adapter extends FirestoreRecyclerAdapter<Types_Item, Types_adapter.RecyclerHolder> {
private final ExpansionLayoutCollection expansionsCollection = new ExpansionLayoutCollection();
Context context;
public Types_adapter(#NonNull FirestoreRecyclerOptions<Types_Item> options, Context context) {
super(options);
expansionsCollection.openOnlyOne(true);
this.context = context;
}
#Override
protected void onBindViewHolder(#NonNull RecyclerHolder holder, int position, #NonNull Types_Item model) {
expansionsCollection.add(holder.getExpansionLayout());
holder.textView.setText(model.getName());
Glide.with(holder.imageView.getContext())
.load(model.getImageURL())
.into(holder.imageView);
CheckedTextView[] textView = new CheckedTextView[model.getProblems().size()];
holder.problems.removeAllViews();
for (int i = 0; i < model.getProblems().size(); i++){
textView[i] = new CheckedTextView(context);
textView[i].setText(model.getProblems().get(i));
textView[i].setPadding(10,10,10,10);
textView[i].setTextSize(15);
int finalI = i;
textView[i].setOnClickListener(v -> {
if (textView[finalI].isChecked()){
textView[finalI].setChecked(false);
textView[finalI].setCheckMarkDrawable(0);
}else {
textView[finalI].setChecked(true);
textView[finalI].setCheckMarkDrawable(R.drawable.checked);
}
});
holder.problems.addView(textView[i]);
}
}
#NonNull
#Override
public RecyclerHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return RecyclerHolder.buildFor(parent);
}
public final static class RecyclerHolder extends RecyclerView.ViewHolder {
private static final int LAYOUT = R.layout.item_types;
ExpansionLayout expansionLayout;
TextView textView;
ImageView imageView;
LinearLayout problems;
public static RecyclerHolder buildFor(ViewGroup viewGroup){
return new RecyclerHolder(LayoutInflater.from(viewGroup.getContext()).inflate(LAYOUT, viewGroup, false));
}
public RecyclerHolder(View itemView) {
super(itemView);
expansionLayout = itemView.findViewById(R.id.expansionLayout);
textView = itemView.findViewById(R.id.type_name);
imageView = itemView.findViewById(R.id.type_image);
problems = itemView.findViewById(R.id.problems_list);
}
public ExpansionLayout getExpansionLayout() {
return expansionLayout;
}
}
}
make an interface class and bind this interface into constructor of adapter class.
public interface CustomDialogListener {
void onItemClicked(CheckedTextView checkedTextView);
}
this is for adapter class
private CustomDialogListener mViewClickListener;
public ProductsAdapter(Context context,boolean status) {
this.context = context;
this.status = status;
this.mViewClickListener = (CustomDialogListener) context;
}
and assign interface class method on your required action like onClick on any view.
textView[i].setOnClickListener(v -> {
if (textView[finalI].isChecked()){
textView[finalI].setChecked(false);
textView[finalI].setCheckMarkDrawable(0);
}else {
textView[finalI].setChecked(true);
textView[finalI].setCheckMarkDrawable(R.drawable.checked);
}
listener.onItemClicked(textView);
});
add implementation of interface in parent activity class and override the interface method.
public class ParentActivity extends AppCompatActivity implements
YourAdapter.CustomDialogListener {
#Override
public void onItemClicked(CheckedTextView checkedTextView) {
//Log.d("Item clicked", checkedTextView.isChecked()+"");
}
}
thats the way to track event of recyclerView.
hope i made myself clear.

How to make the inflated views links to a new activity

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!

How to infinite scroll load more with Recycleview?

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 :)

Android: Implementing mopub native ads in recyclerview gives incorrect item positions and IndexOutOfBoundsException

In my android app I'm trying to implement mopub native ads. Before using these native ads my app was functioning correctly as expected. Now it gives outofbound exceptions and incorrect items when list item is clicked. I'm using recyclerview and using infinite scrolling, it gets item from my api and displays item correctly, but when clicking on item it gives incorrect item.
Here is my recyclerview adapter below.
package com.example.adapters;
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.MyApplication;
import com.example.R;
import com.example.events.ErrorLoadingFeed;
import com.example.events.FeedLoaded;
import com.example.events.LoadMoreFeed;
import com.example.model.Post;
import com.example.model.Pagination;
import com.example.ui.InfoActivity;
import com.example.utils.MyAppConstants;
import com.google.gson.Gson;
import com.squareup.picasso.Picasso;
import java.util.List;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Header;
import retrofit.client.Response;
/**
* Created by starwar on 08/09/15.
*/
public class PostRecycleAdapter extends RecyclerView.Adapter<com.example.adapters.PostRecycleAdapter.PostViewHolder> implements Callback<List<Post>> {
private Context mContext;
private List<Post> mPosts;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
// Pagination
private Pagination mPagination;
public PostRecycleAdapter(Context context, List<Post> posts) {
mContext = context;
mPosts = posts;
}
#Override
public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
PostViewHolder viewHolder = new PostViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(PostViewHolder holder, int position) {
holder.bindPost(mPosts.get(position));
// Here you apply the animation when the view is bound
setAnimation(holder.mPostName, position);
//check for last item
if ((position >= getItemCount() - 1)) {
// Loading next set of list items on scroll
if (mPagination != null && !mPagination.getOutOfRange() && mPagination.getNextPage() != null){
MyApplication.bus.post(new LoadMoreFeed(mPagination));
}
}
}
#Override
public int getItemCount() {
return mPosts == null ? 0 : mPosts.size();
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition)
{
Animation animation = AnimationUtils.loadAnimation(mContext, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
public class PostViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView mPostName;
public ImageView mAnchorImage;
public PostViewHolder(View itemView) {
super(itemView);
mPostName = (TextView) itemView.findViewById(R.id.postName);
mAnchorImage = (ImageView) itemView.findViewById(R.id.anchorImage);
itemView.setOnClickListener(this);
}
public void bindPost(Post post) {
mPostName.setText(post.getName());
String postImage = post.getPostImage();
Picasso.with(mContext)
.load(postImage)
.placeholder(R.drawable.avatar_empty)
.into(mAnchorImage);
}
#Override
public void onClick(View view) {
int position = getAdapterPosition(); // gets item position
Post post = mPosts.get(position);
int postId = post.getId();
String postName = post.getName();
Intent intent = new Intent(mContext, InfoActivity.class);
intent.putExtra(MyAppConstants.POST_ID, postId);
intent.putExtra(MyAppConstants.POST_NAME, postName);
mContext.startActivity(intent);
}
}
#Override
public void success(List<Post> posts, Response response) {
if (mPosts == null) {
mPosts = posts;
} else {
mPosts.addAll(posts);
}
notifyDataSetChanged();
List<Header> headerList = response.getHeaders();
for(Header header : headerList) {
if ("X-Pagination".equals(header.getName())) {
Gson gson = new Gson();
mPagination = gson.fromJson(header.getValue(), Pagination.class);
}
}
MyApplication.bus.post(new FeedLoaded(mPagination));
}
#Override
public void failure(RetrofitError error) {
Log.d("Call", " : Failed => " + error);
MyApplication.bus.post(new ErrorLoadingFeed(error));
}
public void clearData() {
if (mPosts != null) {
mPosts.clear();
notifyDataSetChanged();
}
}
public List<Post> getPosts() {
return mPosts;
}
}
And I'm using guide given here to show ads
https://dev.twitter.com/mopub/native/native-android-sdk-integration
Please help. what I can/should do to resolve this.
Thanks in advance.
I know this is an old question, but I was looking for the answer for a couple of hours. Probably I'll save someone's time with this solution.
If you will look carefully documentation here: https://github.com/mopub/mopub-android-sdk/wiki/Native-Ads-with-Recycler-View you will find this:
If you register any data observers on your original Adapter, you should instead register them on the MoPubRecyclerAdapter so they will receive messages with the adjusted position of content items. If you do not do this, the positions you receive for insertion and removal messages may be inaccurate. Be sure to check isAd(position) and use MoPubRecyclerAdapter#getOriginalPosition if you need the position of the item in your local adapter.
So, to get real position, it is necessary to use MoPubRecyclerAdapter.getOriginalPosition(position_in_your_adapter) method.

Categories

Resources