RecyclerView shows removed data on List - java

I have implemented a RecyclerView with inbox style swipe view. When swiped, I removed the list item using the method below:
public void removeItem(int position) {
countries.remove(position);
notifyItemRemoved(position);
}
Similarly when the FAB is pressed I add data using the method,
public void addItem(String country) {
countries.add(country);
notifyItemInserted(countries.size());
}
However, when I remove a data item by swiping, it is removed from the ArrayList and RecyclerView list, but when I add data by FAB the removed data is still displayed in the list. I checked the ArrayList data set. It is as intended.
In the above screenshot you can see the String Test is the newly added data. The data in last two row I already deleted. It gets randomly displayed.
The complete code of my Adapter and Activity.
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {
private ArrayList<String> countries;
private TextView tv_country;
public DataAdapter(ArrayList<String> countries) {
this.countries = countries;
}
#Override
public DataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
tv_country.setText(countries.get(i));
}
#Override
public int getItemCount() {
return countries.size();
}
public void addItem(String country) {
countries.add(country);
notifyItemInserted(countries.size());
}
public void removeItem(int position) {
countries.remove(position);
notifyItemRemoved(position);
}
public class ViewHolder extends RecyclerView.ViewHolder{
public ViewHolder(View view) {
super(view);
tv_country = (TextView)view.findViewById(R.id.tv_country);
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private ArrayList<String> countries = new ArrayList<>();
private DataAdapter adapter;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews(){
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(this);
recyclerView = (RecyclerView)findViewById(R.id.card_recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
adapter = new DataAdapter(countries);
recyclerView.setAdapter(adapter);
countries.add("Australia");
countries.add("India");
countries.add("United States of America");
countries.add("Germany");
countries.add("Russia");
adapter.notifyDataSetChanged();
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.LEFT){
adapter.removeItem(position);
}
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
Paint p = new Paint();
Bitmap icon;
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
View itemView = viewHolder.itemView;
if(dX > 0){
p.setColor(Color.parseColor("#388E3C"));
c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX,(float) itemView.getBottom(), p);
icon = BitmapFactory.decodeResource(
getResources(), R.drawable.ic_edit_white);
float height = (float) itemView.getBottom() - (float) itemView.getTop();
float width = height / 3;
RectF dest = new RectF((float) itemView.getLeft() + width ,(float) itemView.getTop() + width,(float) itemView.getLeft()+ width+width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,dest,p);
} else {
p.setColor(Color.parseColor("#D32F2F"));
c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(),(float) itemView.getRight(), (float) itemView.getBottom(), p);
icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_delete_white);
float height = (float) itemView.getBottom() - (float) itemView.getTop();
float width = height / 3;
RectF dest = new RectF((float) itemView.getRight() - width - width ,(float) itemView.getTop() + width,(float) itemView.getRight() - width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,dest,p);
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.fab:
adapter.addItem("Test");
Log.d("Raj",countries.toString());
break;
}
}
}
What I have tried
I have tried using notifyItemRangeChanged() like this:
public void removeItem(int position) {
countries.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, countries.size());
}

I can't be sure that this will solve your problem, but one thing that is incorrect is how you are binding your data. tv_country should not be a part of the DataAdapter; it should be a part of each individual ViewHolder. One of the reasons we use the ViewHolder pattern is to maintain an easy reference to the views in each row.
Your bind method should end up similar to:
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
viewHolder.tv_country.setText(countries.get(i));
}
And be sure to make tv_country a public field of your inner ViewHolder class.
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView tv_country;
public ViewHolder(View view) {
super(view);
tv_country = (TextView) view.findViewById(R.id.tv_country);
}
}

Not sure I understood what is happening a 100%, but why are you actually trying to animate yourself? If you implement getItemId() and hasStableIds() if I remember correctly, you just should tell the recyclerview which element was removed or added (like you actually do).

Inside the onSwiped method, add viewHolder.setIsRecyclable(false);

Related

Android ItemTouchHelper notifyItemChanged only works once

I am currently learning android development and I came across a problem that I didn't find a solution.
I have a nested recycler view that groups products. If I swipe right the item get removed and if I swipe left it pops back to the original position and opens a overlay with the edit options.
The problem is that if I swipe left twice the product doesn't pops back.
I am using the notifyItemChanged method to reset the product every time I swipe left.
Current Behavior:
PorductFragmant.java
View view = inflater.inflate(R.layout.fregment_products, container, false);
groups = view.findViewById(R.id.groups);
ArrayList<ProductGroup> productGroups = new ArrayList<>();
ArrayList<Product> products = new ArrayList<>();
products.add(new Product("Product #1", 500, 500));
products.add(new Product("Product #2", 400, 600));
products.add(new Product("Product #3", 500, 500));
products.add(new Product("Product #4", 500, 1000));
productGroups.add(new ProductGroup("Product Group #1", products));
productGroups.add(new ProductGroup("Product Group #1", new ArrayList<>()));
groups.setAdapter(new GroupAdapter(productGroups));
groups.setLayoutManager(new LinearLayoutManager(container.getContext()));
return view;
GroupAdapter.java
public class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.ViewHolder> {
private ArrayList<ProductGroup> groups = new ArrayList<>();
public GroupAdapter(ArrayList<ProductGroup> groups) {
setGroups(groups);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_group, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.group = groups.get(position); // set the group model for the view holder
holder.refresh(); // Refresh data in the view
//Attach Touch Listener
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
ProductAdapter.ViewHolder productHolder = (ProductAdapter.ViewHolder) viewHolder;
productHolder.deleteBg.setVisibility(View.GONE);
productHolder.editBg.setVisibility(View.GONE);
switch (direction){
case ItemTouchHelper.RIGHT: {
//DELETE
holder.group.removeProduct(productHolder.getAdapterPosition()); //Remove the item
groups.set(holder.getAdapterPosition(), new ProductGroup((String) holder.title.getText(), holder.group.getProducts())); // update the group
notifyDataSetChanged(); // Notify Adapter
break;
}
case ItemTouchHelper.LEFT: {
//EDIT
holder.productAdapter.notifyItemChanged(productHolder.getAdapterPosition()); // Notify Item Changed
break;
}
}
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
ProductAdapter.ViewHolder productHolder = (ProductAdapter.ViewHolder) viewHolder; // Cast view holder to product view holder
// update visibility of the item's background
if(isCurrentlyActive || dX != 0){
if(dX < 0){
productHolder.deleteBg.setVisibility(View.GONE);
productHolder.editBg.setVisibility(View.VISIBLE);
}else{
productHolder.editBg.setVisibility(View.GONE);
productHolder.deleteBg.setVisibility(View.VISIBLE);
}
}else{
productHolder.deleteBg.setVisibility(View.GONE);
productHolder.editBg.setVisibility(View.GONE);
}
// update padding for the background
// hide/show the opposite end of the background
if(dX > 100)
productHolder.swipeBg.setPadding(0, 0, 0, 0);
else if(dX > 0)
productHolder.swipeBg.setPadding(0, 0, 100, 0);
else if(dX < -100)
productHolder.swipeBg.setPadding(0, 0, 0, 0);
else if(dX < 0)
productHolder.swipeBg.setPadding(100, 0, 0, 0);
getDefaultUIUtil().onDraw(c, recyclerView, productHolder.container, dX, dY, actionState, isCurrentlyActive);
}
}).attachToRecyclerView(holder.productsView);
}
#Override
public int getItemCount() {
return groups.size();
}
public void setGroups(ArrayList<ProductGroup> groups){
this.groups = groups;
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ProductAdapter productAdapter;
public ProductGroup group;
public ConstraintLayout header;
public ConstraintLayout container;
public TextView title;
public ImageView closeBtn;
public RecyclerView productsView;
private boolean isOpen = false;
public ViewHolder(#NonNull View itemView) {
super(itemView);
header = itemView.findViewById(R.id.header);
container = itemView.findViewById(R.id.groupContainer);
title = itemView.findViewById(R.id.title);
closeBtn = itemView.findViewById(R.id.closeBtn);
productsView = itemView.findViewById(R.id.products);
//Hide products in group and set Layout Manager
productsView.setVisibility(View.GONE);
productsView.setLayoutManager(new LinearLayoutManager(itemView.getContext()));
//Open / Close group
header.setOnClickListener(v -> {
isOpen = !isOpen;
if(isOpen) {
productsView.setVisibility(View.VISIBLE);
closeBtn.setImageDrawable(ContextCompat.getDrawable(itemView.getContext(), R.drawable.ic_arrow_down));
}
else {
productsView.setVisibility(View.GONE);
closeBtn.setImageDrawable(ContextCompat.getDrawable(itemView.getContext(), R.drawable.ic_arrow_left));
}
});
}
public void refresh(){
if(group == null) return;
title.setText(group.getTitle()); // set group title
productAdapter = new ProductAdapter(group.getProducts()); //set product adapter
productsView.setAdapter(productAdapter); // assign the product adapter for the products recycle view
}
}
}
ProductAdapter.java
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ViewHolder>{
private ArrayList<Product> products = new ArrayList<>();
public ProductAdapter(ArrayList<Product> products) {
setProducts(products);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.product, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.product = products.get(position); // set the product model for the view holder
holder.refresh();
}
#Override
public int getItemCount() {
return products.size();
}
public void setProducts(ArrayList<Product> products){
this.products = products;
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public Product product;
public MaterialCardView container;
public ImageView icon;
public TextView title;
public TextView price;
public RelativeLayout imageBox;
public MaterialCardView editImage;
public LinearLayout swipeBg;
public RelativeLayout editBg;
public RelativeLayout deleteBg;
private boolean isOpen = false;
public ViewHolder(#NonNull View itemView) {
super(itemView);
container = itemView.findViewById(R.id.productContainer);
icon = itemView.findViewById(R.id.icon);
title = itemView.findViewById(R.id.title);
price = itemView.findViewById(R.id.price);
imageBox = itemView.findViewById(R.id.imageBox);
editImage = itemView.findViewById(R.id.editImage);
swipeBg = itemView.findViewById(R.id.swipeBg);
editBg = itemView.findViewById(R.id.editBg);
deleteBg = itemView.findViewById(R.id.deleteBg);
//hide things
imageBox.setVisibility(View.GONE);
editBg.setVisibility(View.GONE);
deleteBg.setVisibility(View.GONE);
//show/hide image
container.setOnClickListener(v -> {
isOpen = !isOpen;
imageBox.setVisibility(isOpen ? View.VISIBLE : View.GONE);
});
//Image edit button
editImage.setOnClickListener(v -> {
Toast.makeText(itemView.getContext(), "Edit", Toast.LENGTH_SHORT).show();
});
}
#SuppressLint("SetTextI18n")
public void refresh(){
if(product == null) return;
icon.setImageDrawable(Product.getIconByID(container.getContext(), product.getIconID())); // set icon
price.setText( String.format(Locale.ENGLISH, "%.0f", product.getPrice()) + " Ft"); // set price
title.setText(product.getName()); // set title
//TODO IMAGE
}
}
}
I figured it out.
I had to put a notifyDataSetChanged() after the notifyItemChanged()
********
case ItemTouchHelper.LEFT: {
//EDIT
holder.productAdapter.notifyItemChanged(productHolder.getAdapterPosition()); // Notify Item Changed
notifyDataSetChanged();
break;
}
********

RecyclerView onSwiped behaving randomly

I am trying to develop a functionality like Gmail, where you can swipe to delete.
This is my Main Fragment with recycler view.
public class MainFragment extends Fragment implements RecyclerItemTouchHelper.RecyclerItemTouchHelperListener {
RecyclerView recyclerView;
CoordinatorLayout coordinatorLayout;
RecyclerViewAdapter recyclerViewAdapter = null;
private View view;
private Context context = null;
ArrayList<Note> notes = new ArrayList<>();
ArrayList<Note> allNotes;
FloatingActionButton fab;
boolean isLoading = false;
private MainViewModel mViewModel;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.main_fragment, container, false);
view = root;
recyclerView = view.findViewById(R.id.recyclerView);
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT, this);
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(recyclerView);
return root;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
coordinatorLayout = view.findViewById(R.id.mainContent)
populateNotesView();
}
#Override
public void onResume() {
super.onResume();
}
public void populateNotesView() {
MainViewModel obj = new MainViewModel();
allNotes = obj.getData(getContext());
notes.clear();
for (int i = 0; i < 10 && i < allNotes.size(); i++) {
notes.add(allNotes.get(i));
}
initAdapter(notes);
}
private void initAdapter(ArrayList<Note> notes) {
recyclerViewAdapter = new RecyclerViewAdapter(notes, getFragmentManager());
recyclerView.setAdapter(recyclerViewAdapter);
initScrollListener();
}
#Override
public void onDelete(final RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof RecyclerViewAdapter.ItemViewHolder) {
ArrayList<Note> notesList = allNotes;
String name = notesList.get(viewHolder.getAdapterPosition()).getText();
final Note deletedItem = notesList.get(viewHolder.getAdapterPosition());
final int deletedIndex = viewHolder.getAdapterPosition();
recyclerViewAdapter = new RecyclerViewAdapter(notesList, getFragmentManager());
recyclerViewAdapter.removeItem(viewHolder.getAdapterPosition(), getContext());
Snackbar snackbar = Snackbar.make(coordinatorLayout, name + " removed from cart!", Snackbar.LENGTH_LONG);
snackbar.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
recyclerViewAdapter.restoreItem(deletedItem, deletedIndex, getContext());
getFragmentManager().beginTransaction()
.replace(R.id.mainContent, MainFragment.newInstance())
.commitNow();
}
});
snackbar.setActionTextColor(Color.YELLOW);
snackbar.show();
//Reloading fragment
getFragmentManager().beginTransaction()
.replace(R.id.mainContent, MainFragment.newInstance())
.commitNow();
}
}
}
And this is my RecyclerItemTouchHelper
public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback {
private RecyclerItemTouchHelperListener listener;
private boolean delete = false;
public RecyclerItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) {
super(dragDirs, swipeDirs);
this.listener = listener;
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return true;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder != null) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onSelected(foregroundView);
}
}
#Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
final RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
listener.onDelete(viewHolder, viewHolder.getAdapterPosition());
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
public interface RecyclerItemTouchHelperListener {
void onDelete(RecyclerView.ViewHolder viewHolder, int position);
}
}
Now swiping a recyclerview item, doesn't call the onSwiped method every time. And I'm completely swiping the item.
EDIT: Any new item added is deleted successfully but already added items are not getting deleted.
EDIT 2: Adapter
public void removeItem(int position, Context context) {
MainViewModel obj = new MainViewModel();
obj.deleteData(context, mItemList.get(position).getText());
mItemList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mItemList.size());
}
public void restoreItem(Note item, int position, Context context) {
Util.newInstance().save(context, item.getText());
mItemList.add(position, item);
notifyItemInserted(position);
notifyItemRangeChanged(position, mItemList.size());
}
Any help is appreciated.
Thanks in advance.
The item isn't removed because you are using the original list in onDelete() by using below line of code:
ArrayList<Note> notesList = allNotes;
That means that whenever you delete an item, you just back to the original list.
The second issue is when you undo the deletion using the sanckbar action, you do the same thing by calling this:
populateNotesView();
To solve this, you need to remove the item from the original list you feed the RecyclerView adapter with, and just call notifyItemRemoved() for the removed position.
To do so, change onDelete() to be:
#Override
public void onDelete(final RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof RecyclerViewAdapter.ItemViewHolder) {
String name = allNotes.get(viewHolder.getAdapterPosition()).getText();
final Note deletedItem = allNotes.get(viewHolder.getAdapterPosition());
final int deletedIndex = viewHolder.getAdapterPosition();
allNotes.remove(deletedIndex);
recyclerViewAdapter.notifyItemRemoved(deletedIndex);
Snackbar snackbar = Snackbar.make(coordinatorLayout, name + " removed from cart!", Snackbar.LENGTH_LONG);
snackbar.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
allNotes.add(deletedIndex, deletedItem);
recyclerViewAdapter.notifyItemInserted(deletedIndex);
}
});
}
}

RecyclerView Elements repeating when i use ion library to load images

I am using ion library to load images in recyclerview. But i am facing with a problem. RecyclerView is repeating items. When the image is not loaded in new item it shows previously loaded images. I need to show ProgressBar if image is not loaded. How to achieve this.
Here is my Adapter class:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private String[] links;
private Context context;
private int screen_width;
public RecyclerViewAdapter(Context context, String[] links, int screen_width) {
this.links = links;
this.context = context;
this.screen_width = screen_width;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(R.layout.list_item,viewGroup,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, final int i) {
loadImage(i, viewHolder);
}
private void loadImage(final int pos, final ViewHolder holder) {
Ion.with(context)
.load(links[pos])
.withBitmap()
.placeholder(R.drawable.icon_download_active)
.error(R.drawable.icon_could_not_download)
.fadeIn(true)
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
#SuppressLint("SetTextI18n")
#Override
public void onCompleted(Exception e, Bitmap result) {
if ( e != null ) {
Log.i("IMAGE_LOADER_EV","Failed to load image \n Error:"+e.toString());
} else {
int h = (screen_width * result.getHeight()) / result.getWidth();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(screen_width,h);
params.setMargins(0,0,0,dpToPx(context));
holder.image.setLayoutParams(params);
holder.image.setImageBitmap(result);
}
}
});
}
private static int dpToPx(Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, (float) 5, context.getResources().getDisplayMetrics());
}
#Override
public int getItemCount() {
return links.length;
}
class ViewHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView dimens;
ProgressBar progressBar;
ViewHolder(View view) {
super(view);
image = view.findViewById(R.id.image);
dimens = view.findViewById(R.id.dimens);
progressBar = view.findViewById(R.id.progress_bar);
}
}
}
Recycler shows previous items when the new image is not loaded.
So how to solve this problem?
Finally found solution. Just add following codes to Adapter class:
#Override
public long getItemId(int position) {
return (long) (position);
}
#Override
public int getItemViewType(int position) {
return position;
}
Use:
Ion.with(imageView)
Then remove where you manually set the image in the ImageView in the callback.
.setCallback(...)
Since you are using the callback to manage populating the ImageView, you're creating a race condition where the ImageView is loaded by multiple different items as it is recycled.
Using Ion.with(imageView) allows Ion to track the ImageViews in your RecyclerView and cancel image loads as the ImageViews get recycled.
See sample:
https://github.com/koush/ion#load-an-image-into-an-imageview

change the position of two view (Text view ) using Drag And Drop functionality

i want change the position of Text View using drag and drop functionally in android using Drag listener and animation. i am done a design using following code. i want to change the order of text view using Drag Listener. thanks i give a image of design and i want change position of text view using drag and drop
public void loadtable()
{
Sorting_Linear = (LinearLayout) findViewById(R.id.Sorting_Linear);
submit = (Button) findViewById(R.id.submit);
LinearLayout[] llRow = new LinearLayout[5];
final TextView[] outletnametxt = new TextView[5];
final ImageView[] imageButtonup = new ImageView[5];
final ImageView[] imageButtondown = new ImageView[5];
final LinearLayout[] Linearlayout = new LinearLayout[5];
for (int i = 0; i < 5; i++) {
llRow[i] = new LinearLayout(mContext);
LinearLayout.LayoutParams paramsllRow = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
paramsllRow.setMargins(0, 2, 0, 0);
llRow[i].setLayoutParams(paramsllRow);
llRow[i].setOrientation(LinearLayout.HORIZONTAL);
outletnametxt[i] = new TextView(mContext);
outletnametxt[i].setLayoutParams(nametxt);
outletnametxt[i].setText(olm_name[i]);
outletnametxt[i].setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
outletnametxt[i].setTextSize(20);
outletnametxt[i].setGravity(Gravity.CENTER);
outletnametxt[i].setBackgroundColor(mContext.getResources().getColor(android.R.color.white));
llRow[i].addView(outletnametxt[i]);
imageButtonup[i] = new ImageView(mContext);
imageButtonup[i].setLayoutParams(imagebtnup);
imageButtonup[i].setImageResource(R.drawable.arrowup);
imageButtondown[i] = new ImageView(mContext);
imageButtondown[i].setLayoutParams(imagebtndown);
imageButtondown[i].setImageResource(R.drawable.arrowdown);
Linearlayout[i] = new LinearLayout(mContext);
Linearlayout[i].setLayoutParams(linearlayout);
Linearlayout[i].setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
Linearlayout[i].setBackgroundColor(mContext.getResources().getColor(android.R.color.white));
Linearlayout[i].setOrientation(LinearLayout.VERTICAL);
Linearlayout[i].addView(imageButtonup[i]);
Linearlayout[i].addView(imageButtondown[i]);
llRow[i].addView(Linearlayout[i]);
Sorting_Linear.addView(llRow[i]);
}
Create below interface ItemTouchHelperAdapter
public interface ItemTouchHelperAdapter {
boolean onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);}
Create second interface ItemTouchHelperViewHolder
public interface ItemTouchHelperViewHolder {
void onItemSelected();
void onItemClear();}
Create OnStartDragListener
public interface OnStartDragListener {
void onStartDrag(RecyclerView.ViewHolder viewHolder);}
Create below class
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
public static final float ALPHA_FULL = 1.0f;
private final ItemTouchHelperAdapter mAdapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
#Override
public boolean isLongPressDragEnabled() {
return true;
}
#Override
public boolean isItemViewSwipeEnabled() {
return true;
}
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// Set movement flags based on the layout manager
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
} else {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
// Notify the adapter of the move
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
return true;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
// Notify the adapter of the dismissal
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
// Fade out the view as it is swiped out of the parent's bounds
final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(alpha);
viewHolder.itemView.setTranslationX(dX);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// We only want the active item to change
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
if (viewHolder instanceof ItemTouchHelperViewHolder) {
// Let the view holder know that this item is being moved or dragged
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA_FULL);
if (viewHolder instanceof ItemTouchHelperViewHolder) {
// Tell the view holder it's time to restore the idle state
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemClear();
}
}}
Now just add this code to your recycler view adapter
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new RecyclerListAdapter(Activity_OutletSorting.this, onStartDragListener, olm_name,idopeningclosing);
recyclerView.setAdapter(adapter);
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(recyclerView);

SnapHelper Item Position

I'm using vertical RecyclerView to list my items and SnapHelper to snap center item. The idea is to randomize selection, so user swipe screen or shake the device and it is scrolling to random position.
Number of items is 20, however I use Integer.MAX_VALUE for the number of elements in RecyclerView and initialize RecyclerView with position Integer.MAX_VALUE / 2 to create some kind of endless list.
To scroll to random position on device shake I need to know current snapped item position.
Is there any way to do it?
Here is my Fragment code:
public class PlaceListFragment extends Fragment {
private static final String TAG = "PlaceListFragment";
public static final String ARG_KEY1 = "key1";
private ArrayList<PlaceItem> places;
private RecyclerView recyclerView;
private SensorManager sensorManager;
private float accelValue;
private float accelLast;
private float shake;
SnapHelper snapHelper;
Vibrator vibe;
public static PlaceListFragment newInstance() {
Bundle args = new Bundle();
PlaceListFragment fragment = new PlaceListFragment();
fragment.setArguments(args);
return fragment;
}
public static PlaceListFragment newInstance(ArrayList<PlaceItem> places) {
Bundle args = new Bundle();
args.putParcelableArrayList(PlaceListActivity.KEY_PLACES, places);
PlaceListFragment fragment = new PlaceListFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
places = getArguments().getParcelableArrayList(PlaceListActivity.KEY_PLACES);
accelValue = SensorManager.GRAVITY_EARTH;
accelLast = SensorManager.GRAVITY_EARTH;
shake = 0.00f;
vibe = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_place_list, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.place_list);
snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
recyclerView.setOnFlingListener(snapHelper);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(new PlaceListAdapter(getActivity(), places));
recyclerView.scrollToPosition(PlaceListAdapter.MIDDLE);
sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE);
sensorManager.registerListener(sensorListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);
return v;
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onPause() {
super.onPause();
}
private final SensorEventListener sensorListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
accelLast = accelValue;
accelValue = (float) Math.sqrt((double) (x*x + y*y + z*z));
float delta = accelValue - accelLast;
shake = shake * 0.9f + delta;
if (shake > 12) {
vibe.vibrate(200);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
}
And here is adapter:
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.PlaceAdapterHolder> {
private final FragmentActivity context;
public static final int HALF_MAX_VALUE = Integer.MAX_VALUE/2;
public static int MIDDLE;
private List<PlaceItem> placeItems;
public static class PlaceAdapterHolder extends RecyclerView.ViewHolder {
private ImageView image;
private TextView textMain;
private TextView textRating;
public PlaceAdapterHolder(View itemView) {
super(itemView);
image = (ImageView) itemView.findViewById(R.id.icon);
textMain = (TextView) itemView.findViewById(R.id.txt_main_line);
textRating = (TextView) itemView.findViewById(R.id.txt_right_field);
}
public void bindPlace(PlaceItem placeItem) {
String placeName = placeItem.getName() == null? "?":placeItem.getName();
String firstLetter = placeName.substring(0, 1);
ColorGenerator generator = ColorGenerator.MATERIAL; // or use DEFAULT
int color = generator.getColor(placeName);
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.toUpperCase()
.endConfig()
.buildRect(firstLetter, color);
image.setImageDrawable(drawable);
textMain.setText(placeItem.getName());
textRating.setText(placeItem.getRating());
}
}
public PlaceListAdapter(FragmentActivity context, List<PlaceItem> placeItems) {
this.context = context;
this.placeItems = placeItems;
MIDDLE = HALF_MAX_VALUE - HALF_MAX_VALUE % placeItems.size();
}
#Override
public PlaceListAdapter.PlaceAdapterHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.place_list_one_line_item, parent, false);
return new PlaceAdapterHolder(view);
}
#Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
#Override
public void onBindViewHolder(PlaceListAdapter.PlaceAdapterHolder holder, final int position) {
final PlaceItem placeItem = getItem(position);
holder.bindPlace(placeItem);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fm = context.getSupportFragmentManager();
PlaceDetailsFragment dialog = PlaceDetailsFragment.newInstance(getItem(position));
dialog.show(fm, "DETAILS_DIALOG");
}
});
}
private PlaceItem getItem(int position)
{
return placeItems.get(position % placeItems.size());
}
}
I used this on a project that had a RecyclerView with SnapHelper, not sure if it is what you want.
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mAdapter = new DemoSlidesAdapter(getApplicationContext());
mRecyclerView.setAdapter(mAdapter);
final SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(mRecyclerView);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
View centerView = snapHelper.findSnapView(mLayoutManager);
int pos = mLayoutManager.getPosition(centerView);
Log.e("Snapped Item Position:",""+pos);
}
}
});
I try to use this code with a PagerSnapHelper to mimic the pager behaviour and it was useful but i found some corner cases to solve, if you move fast from the last page to the first one and keep swapping until see the boundarie then the IDLE state doesnt happen and you lose your index. to solve that I move out the position from the IF and add a extra condition for this corner case.
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val centerView = snapHelper.findSnapView(mLayoutManager)
val pos = mLayoutManager.getPosition(centerView!!)
if (newState == RecyclerView.SCROLL_STATE_IDLE || (pos == 0 && newState == RecyclerView.SCROLL_STATE_DRAGGING)) {
Log.d("BINDING", "positionView SCROLL_STATE_IDLE: $pos")
}
}
Code is in kotlin hope it helps
private fun recyclerViewScrollListener() = object: RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// layoutManager is LinearLayoutManager
val pos = layoutManager.findFirstCompletelyVisibleItemPosition()
Log.e(TAG, "onScrollStateChanged: $pos")
}
}
}
recyclerView.setOnScrollListener(recyclerViewScrollListener())
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
....
}
})

Categories

Resources