I have a Recyclerview and there are Imageviews in it. When I click any of image, I want to make visible a number of information about image on the image.
Well, I did it but it seems everything's happening randomly... When I click first image, informations appearing on the second, when I click on the second its working normally and when I click third, nothing happening etc.
Here is some of my code;
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
myViewHolder = new MyViewHolder(view);
myViewHolder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isUp) {
slideDown(myViewHolder.infoView);
} else {
slideUp(myViewHolder.infoView);
}
isUp = !isUp;
}
});
return myViewHolder;
}
class MyViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public MyViewHolder(View itemView) {
super(itemView);
init();
}
void init() {
imageView = itemView.findViewById(R.id.imageViewID);
...
}
}
It seems I should group some elements or is there any better idea, way ?
Slide method;
// slide the view from below itself to the current position
public void slideUp(View view) {
view.setVisibility(View.VISIBLE);
infoView.animate().alpha(1.0f).setDuration(500);
ScaleAnimation animate = new ScaleAnimation(
1f, 1f, // Start and end values for the X axis scaling
0f, 1f, // Start and end values for the Y axis scaling
Animation.RELATIVE_TO_SELF, 0f, // Pivot point of X scaling
Animation.RELATIVE_TO_SELF, 1f); // toYDelta
animate.setDuration(800);
animate.setFillAfter(true);
view.startAnimation(animate);
}
I moved onClickListener method to onBindViewHolder and thats what make sense but result did not change.
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.textView_name.setText(nameElement.get(position).text());
Picasso.get().load(imageElement.get(position).absUrl("src")).fit().into(holder.imageView);
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isUp) {
myViewHolder.slideDown(myViewHolder.infoView);
} else {
myViewHolder.slideUp(myViewHolder.infoView);
}
isUp = !isUp;
}
});
}
You need to add slideUp slideDown methods in MyViewHolder class
and I think no need to implement click listener in onBindViewHolder, just put it in the init function.
void init() {
imageView = itemView.findViewById(R.id.imageViewID);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isUp) {
slideDown(v);
} else {
slideUp(v);
}
isUp = !isUp;
}
});
}
hope it works!!!
You should add listener for the ViewHolder in onBindViewHolder, and not onCreateViewHolder
First of all, it's better to define onClickListener in onBindViewHolder
Second, store the data on a POJO class, and save last states,
so you can keep the last state of an item(isUP or !)
for example, you have this model:
class ImageModel {
private String imageURI;
private Boolean isUP ;
//getter setters
}
then if you pass a list of ImageModel into your adapter, you can easily change the isUP
and on your adapter change the state of imageviews based on isUP
if (model.isUp) {
slideDown(myViewHolder.infoView);
} else {
slideUp(myViewHolder.infoView);
}
Related
So when i click on the 0 position of recyclerview to change the color of the view it also changes the color at 8th, 16th and 24th position (i have a total of 26 items in recyclerview), if i click on position 1 it changes color at 1st, 9th, 17th and 25th and so on. how do i fix this
My recyclerview adapter is
public class AdapterOccupiedRoomCleaning extends RecyclerView.Adapter<AdapterOccupiedRoomCleaning.ViewHolder> {
private List<ItemsAdapter> mList;
private Context mContext;
public AdapterOccupiedRoomCleaning(List<ItemsAdapter> list, Context context){
super();
mList = list;
mContext = context;
}
#NonNull
#Override
public AdapterOccupiedRoomCleaning.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.occupiedrooms_cleaning_item, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
((ViewHolder) viewHolder).setUrduText.setText(itemAdapter.getUrdutext());
((ViewHolder) viewHolder).setEnglishText.setText(itemAdapter.getEnglishText());
((ViewHolder) viewHolder).setCleaningImage.setImageResource(itemAdapter.getImage());
// ((ViewHolder) viewHolder).background.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
//
// //viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
//
// Toast.makeText(mContext, "Recycle Click " + viewHolder.setEnglishText.getText().toString(), Toast.LENGTH_SHORT).show();
// }
// });
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
#Override
public int getItemCount() {
//notifyDataSetChanged();
return mList.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public TextView setUrduText, setEnglishText;
public ImageView setCleaningImage;
public View background;
public ViewHolder(View itemView) {
super(itemView);
setUrduText = (TextView) itemView.findViewById(R.id.urduTextView);
setEnglishText = (TextView) itemView.findViewById(R.id.englishTextView);
setCleaningImage = (ImageView) itemView.findViewById(R.id.imageCleaning);
background = (View) itemView.findViewById(R.id.backgroundColor);
}
}
}
My java class is
public class OccupiedRoomCleaning extends AppCompatActivity {
String getQrCode, patientMRNO, roomNumber;
private RecyclerView mRecycleview;
private List<ItemsAdapter> mList = new ArrayList<>();
private AdapterOccupiedRoomCleaning mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_occupied_room_cleaning);
getQrCode = getIntent().getExtras().getString("qrcode");
init();
addList();
adapter();
}
private void init(){
mRecycleview = findViewById(R.id.recyclerview);
}
private void addList(){
ItemsAdapter itemAdapter = new ItemsAdapter();
itemAdapter.setImage(R.drawable.pillowclean);
itemAdapter.setUrdutext("sdf");
itemAdapter.setEnglishText("Pillow Parachute Cover Cleaning");
mList.add(itemAdapter);
itemAdapter = new ItemsAdapter();
itemAdapter.setImage(R.drawable.bedclean);
itemAdapter.setUrdutext("sdfs");
itemAdapter.setEnglishText("Patient Bed Cleaning(Blood Spots)");
mList.add(itemAdapter);
//... more items
}
private void adapter(){
Log.d("anhtt","mlist : " +mList.size());
mAdapter = new AdapterOccupiedRoomCleaning(mList, this);
mRecycleview.setAdapter(mAdapter);
mRecycleview.setLayoutManager(new LinearLayoutManager(this));
}
}
what am i doing wrong here that it changes color at every 8th item
This seems likely to be a problem with the view recycling behavior of RecyclerView.
Generally, you're going to run into problems like this one any time you have some property of your ViewHolder that you only conditionally set inside onBindViewHolder(). That is, because you do not always update the background color of your ViewHolder, you'll get the "wrong" color when it is recycled and reused.
You will have to somehow store the "clicked" or "selected" state in your list of items, and then update the background color of your ViewHolder every time in onBindViewHolder(). Something like this:
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
...
if (itemAdapter.isSelected()) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
} else {
viewHolder.background.setBackgroundColor(Color.parseColor("#FFFFFF"));
}
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemAdapter.setSelected(true);
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
Note that it would be better to define the click listener inside onCreateViewHolder() and to use notifyItemChanged() instead of manually updating the background color, but that's outside the scope of this question.
Since, a Recycler view reuses the views and do not create new views, you need to set default color in onBindViewHolder function.
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
((ViewHolder) viewHolder).setUrduText.setText(itemAdapter.getUrdutext());
((ViewHolder) viewHolder).setEnglishText.setText(itemAdapter.getEnglishText());
((ViewHolder) viewHolder).setCleaningImage.setImageResource(itemAdapter.getImage());
// Add this line
((ViewHolder) viewHolder).background.setBackgroundColor(Color.parseColor("default color"));
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
I've been searching for a solution for three days now.
If everyone has an Idea please help me, I don't even think it's actually that difficult to achieve but It's not really my branch, if you can say it like this.
In a RecyclerView containing a list with multiple Items, each having a Title(TextView) and a Cover image(ImageView).
This data is set in the Adapter, in the ViewHolder, more specifically in the OnBind function.
So where's my problem?
I've created a PopUp Window, which contains besides a few buttons, a placeholder ImageView and a placeholder TextView.
I cannot seem to find a way to place the data of the clicked Item in the list inside the placeholders.
I think it's similar to the OnBind method but it doesn't work.
Here's the Adapter (if the code for GameItem is needed I'll gladly post it):
import java.util.ArrayList;
public class GameViewAdapter extends RecyclerView.Adapter<GameViewAdapter.GameViewHolder> {
private ArrayList<GameItem> mGameList;
private OnItemClickListener mListener;
public interface OnItemClickListener{
void onGameClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
mListener =listener;
}
public static class GameViewHolder extends RecyclerView.ViewHolder{
public ImageView Cover;
public TextView Title;
public TextView Description;
public PopupWindow popupWindow;
public ImageView popUpImage;
public TextView PopUpTitle;
public EditText customAmount;
public Button add;
private Button addcustom;
private Button exit;
public GameViewHolder(final View itemView, final OnItemClickListener listener) {
super(itemView);
add = itemView.findViewById(R.id.addaverage);
addcustom = itemView.findViewById(R.id.addcustom);
popUpImage = itemView.findViewById(R.id.popupimg);
PopUpTitle = itemView.findViewById(R.id.popuptitle);
customAmount = itemView.findViewById(R.id.gameamount);
Cover = itemView.findViewById(R.id.GameCover);
Title = itemView.findViewById(R.id.GameTitle);
Description = itemView.findViewById(R.id.GameAmount);
exit = itemView.findViewById(R.id.exit);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showPopUp();
}
});
}
public void showPopUp() {
final View popupView = LayoutInflater.from(itemView.getContext()).inflate(R.layout.popup, null);
final PopupWindow popupWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
exit = popupView.findViewById(R.id.exit);
exit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
}
}
public GameViewAdapter(ArrayList<GameItem> gameList){
mGameList = gameList;
}
#Override
public GameViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
View v = LayoutInflater.from(context).inflate(R.layout.game_entry, viewGroup, false);
GameViewHolder GVH = new GameViewHolder(v, mListener);
return GVH;
}
#Override
public void onBindViewHolder(#NonNull GameViewHolder gameViewHolder, int position){
GameItem currentItem = mGameList.get(position);
Glide.with(gameViewHolder.Cover).load(currentItem.getCover()).into(gameViewHolder.Cover);
gameViewHolder.Title.setText(currentItem.getTitle());
gameViewHolder.Description.setText(currentItem.getDescription());
}
#Override
public int getItemCount() {
return mGameList.size();
}
}
In the OnBind method, the Image and Text are associated to the Items
correctly, through Glide and
gameViewHolder.Title.setText(currentItem.getTitle());. Now, I have
created a PopUp, which should get the Image and the Text from the
clicked item in the RecyclerView.
I've reordered some methods and properties for the sake of clarity and then next, I'll explain.
public class GameViewAdapter extends RecyclerView.Adapter<GameViewAdapter.GameViewHolder> {
private ArrayList<GameItem> mGameList;
private OnItemClickListener mListener;
public GameViewAdapter(ArrayList<GameItem> mGameList, GameViewAdapter.OnItemClickListener mListener) {
this.mGameList = mGameList;
this.mListener = mListener;
}
#Override
public GameViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
View v = LayoutInflater.from(context).inflate(R.layout.game_entry, viewGroup, false);
GameViewHolder GVH = new GameViewHolder(v, mListener);
return GVH;
}
#Override
public void onBindViewHolder(#NonNull GameViewHolder gameViewHolder, int position){
gameViewHolder.bind(mGameList.get(position));
}
#Override
public int getItemCount() {
return mGameList.size();
}
class GameViewHolder extends RecyclerView.ViewHolder {
private ImageView itemCover;
private TextView itemTitle;
private TextView itemDescription;
private PopupWindow popupWindow;
private ImageView popUpImage;
private TextView PopUpTitle;
private EditText customAmount;
private Button add;
private Button addcustom;
private Button exit;
public GameViewHolder(View itemView, GameViewAdapter.OnItemClickListener mListener) {
super(itemView);
setupViews(itemView);
}
public void bind(GameItem gameItem) {
Glide.with(this.itemCover).load(gameItem.getCover()).into(this.itemCover);
this.itemTitle.setText(gameItem.getTitle());
this.itemDescription.setText(gameItem.getDescription());
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showPopUp(itemView, gameItem);
}
});
}
private void setupViews(View itemView) {
add = itemView.findViewById(R.id.addaverage);
addcustom = itemView.findViewById(R.id.addcustom);
popUpImage = itemView.findViewById(R.id.popupimg);
PopUpTitle = itemView.findViewById(R.id.popuptitle);
customAmount = itemView.findViewById(R.id.gameamount);
itemCover = itemView.findViewById(R.id.GameCover);
itemTitle = itemView.findViewById(R.id.GameTitle);
itemDescription = itemView.findViewById(R.id.GameAmount);
exit = itemView.findViewById(R.id.exit);
}
private void showPopUp(View itemView, GameItem gameItem) {
final View popupView = LayoutInflater.from(itemView.getContext()).inflate(R.layout.popup, null);
final PopupWindow popupWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
final ImageView popupItemCover = popupView.findViewById(R.id.popupItemCover);
final TextView popupItemTitle = popupView.findViewById(R.id.popupItemTitle);
Glide.with(popupItemCover).load(gameItem.getCover()).into(popupItemCover);
popupItemTitle.setText(gameItem.getTitle());
exit = popupView.findViewById(R.id.exit);
exit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
}
}
public interface OnItemClickListener{
void onGameClick(int position);
}
}
What changed?
First, we now have a method called bind inside our ViewHolder, we took the responsibility from setting the data from our Adapter and delegated it to the ViewHolder.
Second, as that method is called every time onBindViewHolder is called, you'll have the actual GameItem. So? With that item, instead of setting the onClickListener to open the PopUp in the GameViewHolderconstructor, we now set it in the bind method. But, what are the benefits from it? Every time we bind data to its views, we prepare our Popup and then show it.
What should be changed?
For performance purposes, I guess, you should instantiate the constructor and then populate it every time with new data, instead of creating a new instance again every time onBindViewHolder is called.
Edit: As I don't know your popup views IDs, I've created some dummies IDs. Hope you understand.
Best.
I am trying to implement a horizontal recycleview with right and left arrow indicators. So what happens is if one clicks the right arrow next item should appear and if one clicks the left arrow the previous item should appear and also at the end of the list the left arrow should disappear. I have no Idea how ti implement this. can someone help me out? Below is my Horizontal Recyclerview adapter.
public class DialogRecyclerViewAdapter extends RecyclerView.Adapter<DialogRecyclerViewAdapter.ViewHolder> {
Context context;
List<UploadImage> dataAdapters;
private SharedPreferences.Editor mSharedPrefEditor;
ImageLoader imageLoader;
public DialogRecyclerViewAdapter(List<UploadImage> getDataAdapter, Context context){
super();
this.dataAdapters = getDataAdapter;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder Viewholder, int position) {
final UploadImage dataAdapterOBJ = dataAdapters.get(position);
imageLoader = ImageAdapter.getInstance(context).getImageLoader();
imageLoader.get(dataAdapterOBJ.getImage(),
ImageLoader.getImageListener(
Viewholder.VollyImageView,//Server Image
R.drawable.loading_1,//Before loading server image the default showing image.
android.R.drawable.ic_dialog_alert //Error image if requested image dose not found on server.
)
);
Viewholder.VollyImageView.setImageUrl(dataAdapterOBJ.getImage(), imageLoader);
Viewholder.ImageTitleTextView.setText(dataAdapterOBJ.getBrand_name());
Viewholder.garment_price.setText(dataAdapterOBJ.getGarment_price());
Viewholder.VollyImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MihuChatApplication.getInstance().getContext());
mSharedPrefEditor = sharedPref.edit();
mSharedPrefEditor.putString(Constants.KEY_FROM_CHAT, "fromChatWIndow").apply();
Intent i=new Intent(MihuChatApplication.getInstance().getContext(), DetailsNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//PACK DATA TO SEND
i.putExtra("image_title",dataAdapterOBJ.getGarment_name());
i.putExtra("image_url",dataAdapterOBJ.getImage_full());
i.putExtra("desc_text", dataAdapterOBJ.getDesc_text());
//i.putExtra("image_url2", imageLarger);
i.putExtra("image_price", dataAdapterOBJ.getGarment_price());
//i.putExtra("disc_price", disc_price);
//open activity
MihuChatApplication.getInstance().getApplicationContext().startActivity(i);
}
});
}
#Override
public int getItemCount() {
return dataAdapters.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public TextView ImageTitleTextView, garment_price;
public NetworkImageView VollyImageView ;
public ViewHolder(View itemView) {
super(itemView);
garment_price = (TextView) itemView.findViewById(R.id.garment_price);
ImageTitleTextView = (TextView) itemView.findViewById(R.id.ImageNameTextView) ;
VollyImageView = (NetworkImageView) itemView.findViewById(R.id.VolleyImageView) ;
}
}
}
Thanks in advance.
Try the following
here img_LeftScroll is the left imageview and img_right_scroll is the right imageview between the horizontal list, rv_horizontal is the horizontallist view
then onclick of the image view do the below, hope it works
img_LeftScroll.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (horizontalLayoutManagaer.findFirstVisibleItemPosition() > 0) {
rv_horizontal.smoothScrollToPosition(horizontalLayoutManagaer.findFirstVisibleItemPosition() - 1);
} else {
rv_horizontal.smoothScrollToPosition(0);
}
}
});
img_right_scroll.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rv_horizontal.smoothScrollToPosition(horizontalLayoutManagaer.findLastVisibleItemPosition() + 1);
}
});
Horizontal Recycler view with left and right arrow Indicators --I have Done this By creating a custom Layout with recyclerVIew and two arrow images --
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case SCROLL_STATE_DRAGGING:
//Indicated that user scrolled.
programaticallyScrolled = false;
break;
case SCROLL_STATE_IDLE:
if (!programaticallyScrolled) {
currentVisibleItem = linearLayoutManager.findFirstCompletelyVisibleItemPosition();
handleWritingViewNavigationArrows(false);
}
break;
default:
break;
}
}
});
Hide/Show navigation arrows
/**
* Handles the arrows visibility based on current visible items and scrolls the
* current visibility item based on param scroll.
*
* Scroll - is False if User scrolls the Reycler Manually
* - is True means User used arrows to navigate
*
* #param scroll
*/
private void handleWritingViewNavigationArrows(boolean scroll) {
if (currentVisibleItem == (recyclerView.getAdapter().getItemCount() - 1)) {
rightArrow.setVisibility(View.GONE);
leftArrow.setVisibility(View.VISIBLE);
} else if (currentVisibleItem != 0) {
rightArrow.setVisibility(View.VISIBLE);
leftArrow.setVisibility(View.VISIBLE);
} else if (currentVisibleItem == 0) {
leftArrow.setVisibility(View.GONE);
rightArrow.setVisibility(View.VISIBLE);
}
if (scroll) {
recyclerView.smoothScrollToPosition(currentVisibleItem);
}
}
Check the example for the reference hope it helps u
https://github.com/RameshBhupathi/RecyclerViewWithLeftAndRightArrowsExample
This code works in my case:
btn_to_right.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
p = linearLayoutManager.findFirstVisibleItemPosition() - 1;
recyclerview.smoothScrollToPosition( p);
checkVisibility();
}
});
btn_to_left.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
p = linearLayoutManager.findLastVisibleItemPosition() + 1;
recyclerview.smoothScrollToPosition(p);
checkVisibility();
}
});
public void checkVisibility() {
if (p < 1) {
btn_to_right.setVisibility(View.GONE);
btn_to_left.setVisibility(View.VISIBLE);
} else if (p >= (recyclerview.getAdapter().getItemCount() - 1)) {
btn_to_right.setVisibility(View.VISIBLE);
btn_to_left.setVisibility(View.GONE);
} else {
btn_to_right.setVisibility(View.VISIBLE);
btn_to_left.setVisibility(View.VISIBLE);
}
}
Much simpler approach for hiding/showing arrows:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (manager.findFirstCompletelyVisibleItemPosition()==0){
leftArrow.setVisibility(View.INVISIBLE);
}else{
leftArrow.setVisibility(View.VISIBLE);
}
if (manager.findLastCompletelyVisibleItemPosition()==list.size()-1){
rightArrow.setVisibility(View.INVISIBLE);
}else
rightArrow.setVisibility(View.VISIBLE);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
I'm building a change animation for my RecyclerView. I've overriden canReuseUpdatedViewHolder() to return true in order to retain the previous viewholder. I start the animation in animateChange() and call dispatchAnimationFinished() as soon as it ends. Params oldHolder and newHolder are the same instance in animateChange().
Then, as soon as the animation starts, RecyclerView's onBindViewHolder() is called for every child in the list. Surprisingly, only for the animated item a new ViewHolder is spawned in onCreateViewHolder() which as I've understood is not the correct behavior. For every other child the old ViewHolder is bound in onBindViewHolder().
As a side note, onBindViewHolder() is called too soon, before the animation is finished. Even if dispatchAnimationFinished(holder) is called after the animation is finished.
Here's the ItemAnimator subclass.
public class CustomItemAnimator extends DefaultItemAnimator {
#Override
public boolean canReuseUpdatedViewHolder(#NonNull RecyclerView.ViewHolder viewHolder) {
return true;
}
#Override
public boolean canReuseUpdatedViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, #NonNull List<Object> payloads) {
return true;
}
#Override
public boolean animateChange(#NonNull RecyclerView.ViewHolder oldHolder, #NonNull RecyclerView.ViewHolder newHolder, #NonNull ItemHolderInfo preLayoutInfo, #NonNull ItemHolderInfo postLayoutInfo) {
CustomHolder holder = (CustomHolder) newHolder;
CustomView customView = holder.customView;
Animator animator = customView.revealAnimation();
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
dispatchAnimationFinished(holder);
}
});
animator.start();
return false;
}
}
and here's the custom view animation code:
CustomView.java
public Animator revealAnimation() {
return circularRevealView(visibleView, hiddenView);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private Animator circularRevealView(View visibleView, View invisibleView) {
// get the center for the clipping circle
int cx = visibleView.getWidth() / 2;
int cy = visibleView.getHeight() / 2;
// get the final radius for the clipping circle
float finalRadius = (float) Math.hypot(cx, cy);
// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(invisibleView, cx, cy, 0, finalRadius);
visibleView.setVisibility(INVISIBLE);
invisibleView.setVisibility(View.VISIBLE);
// return the animation for later use
return anim;
}
Thanks.
animateChange(...) is called after notifyDataSetChanged(),it means that onBindViewHolder() goes before animateChange(...).and the state of holder has already changed.maybe you can do it this
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
visibleView.setVisibility(INVISIBLE);
invisibleView.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
dispatchAnimationFinished(holder);
}
});
I'm setting a RecyclerView behaving like a list, I want a button in the bottom of the list that when clicked adds more views, I'm thinking the easier way to do it is to make the position 0 as the first one in the bottom, and increasing the position to the top, so I can add views when the the view in position 0 is clicked.
If there is a better aproach for this problem do share.
Here is my adapter:
public class AddEventsAdapter extends RecyclerView.Adapter<AddEventsAdapter.ViewHolder> {
public List<String> items = new ArrayList<>();
public void addItem(String name) {
notifyItemInserted(items.size() - 1);
items.add(name);
}
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, items.size());
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.add_event_item, parent, false);
return new ViewHolder(view);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setData(position);
holder.eventName.setText(i + "");
if(position == 0)
{
holder.theLayout.setBackgroundColor(Color.parseColor("#7F9099"));
holder.eventName.setText("Add");
}
}
static int i;
class ViewHolder extends RecyclerView.ViewHolder{
public TextView eventName;
public RelativeLayout theLayout;
public ViewHolder(final View itemView) {
super(itemView);
eventName = (TextView)itemView.findViewById(R.id.eventName);
theLayout = (RelativeLayout)itemView.findViewById(R.id.backgroundevent);
theLayout.setId(++i);
}
public void setData(final int position) {
theLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (position == items.size() - 1) {
addItem("");
} else {
removeItem(position);
}
}
});
}
}
}
You may notice some errors in that, I've been over it for the last 10 hours and I'm having a logic breakdown
It's solved by addind this line to the LayoutManager .setReverseLayout(true);
you can add a footer view at the end of the list and inside that you can add your button. This is the link to create a footer in recycler view https://github.com/u3breeze/android-RecyclerView-WithHeaderAndFooter. You can add the views in the normal way