How handle recyclerView body clickListener - android

I can't handle clicks on recycerView body (NOT ITEMS),
but when I setOnClickListener on my recycler, it does not work.
I tried clickable="true" in xml, but does not work.
recycler.setOnClickListener {
Toast.makeText(context,"Click on recyclerView",Toast.LENGTH_SHORT).show()
}

Just use a Touch Listener :
recyclerView.setOnTouchListener { _, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
Toast.makeText(context, "Clicked", LENGTH_SHORT).show()
true
}
else -> false
}
}

You need to pass your click listener on "onBindViewHolder()"
That way you will be able to receive where the user clicked and perform something with it.
public void onBindViewHolder(LanguageAdapter.ViewHolder holder, final int position) {
final String name = names.get(position);
holder.main_item_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
});
}
And what you want to do is to set the click listener on your root layout from your items

Related

Android enable/disable spinner touch listener at condition

I have an activity with a Spinner (with his own adapter) and another Adapter that manages the recycler view with its list . I'm trying to implement the following logic : when the list of the recycler is empty the spinner should be enabled , otherwise it should be disabled until the list is empty again :
sGames.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (pokemonCardsGridAdapter.getItemCount() == 0) {
v.performClick();
v.setEnabled(true);
} else {
v.setEnabled(false);
Toast.makeText(PokemonTeambuilderEditorActivity.this, "The list is full", Toast.LENGTH_SHORT).show();
}
return false;
}
});
However , this only works the first time , once the spinner gets disabled , it never receive any touch events again . How can I fix this?
Solved using registerAdapterDataObserver:
pokemonCardsGridAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
public void onChanged() {
sGames.setEnabled(false);
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
if (pokemonCardsGridAdapter.getItemCount() == 0) {
sGames.setEnabled(true);
}
}
});

How to undo delete from Room database

I'm trying to implement the undo delete on a snackbar when a recycler item is swiped by caching the item before its deleted and if undo is clicked, item should be added to recyclerview from cache.
or if there's a better way to achieve this.
Here's my current code
#Override
public void onSwiped(#NonNull final RecyclerView.ViewHolder viewHolder, int direction) {
viewModel = ViewModelProviders.of(Objects.requireNonNull(getActivity())).get(ViewModel.class);
viewModel.getAllAppointments().observe(getViewLifecycleOwner(), new Observer<List<Appointments>>() {
#Override
public void onChanged(List<Appointments> appointments) {
mAdapter.submitList(appointments);
}
});
Snackbar.make(Objects.requireNonNull(getView()), "Appointment deleted", Snackbar.LENGTH_LONG)
.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
//undo delete
}
})
.setActionTextColor(getResources().getColor(R.color.colorPrimaryDark))
.addCallback(new Snackbar.Callback(){
#Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
if (event == DISMISS_EVENT_TIMEOUT || event == DISMISS_EVENT_SWIPE
|| event == DISMISS_EVENT_CONSECUTIVE || event == DISMISS_EVENT_MANUAL) {
viewModel.delete(mAdapter.getAppointAt(viewHolder.getAdapterPosition()));
}
}
})
.show();
}
For doing this work you can call show snackbar in onClick button, so when finish time snackbar invoke delete function (delete from adapter, list, and database or data source), so before this time use can remove item just from adapter temporally for only animat similar (not remove from list) and if user clicked on undo button doing refresh list from database or your data source

recyclerview item changes button style after scroll

I have a recyclerview with simple items - an item has an image, title and a button. When the user clicks on the button it needs to change its layout -> indicating that button is clicked (similar to checkbox functionality).
Problem is that when I click on a button, for example the second item, it behaves weirdly when I scroll - multiple items are toggled or the original one is untoggled. You can check it out in image here:
GIF PREVIEW
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
holder.button.setOnClickListener(view -> {
toggleButtonStyle((Button)view);
});
}
public void toggleButtonStyle(Button toggle)
{
Context ctx = toggle.getContext();
if (toggle.isActivated()) {
toggle.setActivated(false);
toggle.setBackground(ContextCompat.getDrawable(ctx, R.drawable.btn_purple_corners));
toggle.setTextColor(ContextCompat.getColor(ctx, R.color.purple_light));
} else {
toggle.setActivated(true);
toggle.setBackground(ContextCompat.getDrawable(ctx, R.drawable.btn_purple));
toggle.setTextColor(ContextCompat.getColor(ctx, R.color.white));
}
}
You need to specify position for a onBindView method, because it's called multiple times. If you are using AutoValue immutable types, you can try to make an Array of booleans where you'll be storing toggled states (true/false). Then in onBindViewMethod check a value of current position and style a button.
private boolean[] toggledChoices = new boolean[yourListWithItems.size()];
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (toggledChoices[position]) {
toggleButtonStyle(true, holder.toggleButton);
} else {
toggleButtonStyle(false, holder.toggleButton;
}
holderVote.bToggleItem.setOnClickListener(v -> {
if (!toggledChoices[position]) {
toggledChoices[position] = true;
} else {
toggledChoices[position] = false;
}
});
}
I had some strange behavior too in the past.
For me it was solved by simply calling
toggle.invalidate();
after your if/else block. This forces the redraw. Try it, I was surprised too, that this fixed it for me.
Check Out my code
#Override
public void onBindViewHolder(GifGridAdapter.ViewHolder holder, final int position) {
final DataModel model = arrayList.get(position);
if (model.isToggle()) {
//Code for changing the button background color and text color
} else {
//Code for changing the button background color and text color
}
holder.ivGif.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
model.setToggle(!model.isToggle());
notifyDataSetChanged();
}
});
}

Hide the view in recyclerview's item

i facing a problem in recyclerview's item.
My Adapter's code :
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
Log.d("TAG", "CEK : " + viewable);
if(viewable==true){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewable = true;
Log.d("TAG", "CEK 2 : " + viewable);
}
});
}
Like my code above, I want to hide mFormBookingan after mSendBooking has pressed. mFormBookingan never show anymore until user calls it again.
I have tried with a lot of ways but still can't find like what i need. After i press mSendBooking the form hide, but when i send new item to recyclerview, the from mFormBookingan that has been hide, appears again.
My Question, how to hide mFormBookingan forever? Until user call it again.
Thank in advance, i will appreciate anyone who help me for this one.
I not sure what the clear situation you want.
But if you want to set View invisible you can try this code then check it.
You need to add ismFormBookingVisible in viewHolder class as a boolean attribute.
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
Log.d("TAG", "CEK : " + viewable);
if(holder.ismFormBookingVisible==true){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.ismFormBookingVisible = false;
Log.d("TAG", "CEK 2 : " + viewable);
}
Try this :
Create a boolean in your model class "Profile" to keep track of visibility of button : say boolean isBookingVisible;
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
if(!item.isBookingVisible){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
item.isBookingVisible = false;
//Use notiyItemChanged(position); or notifyDataSetChanged(); here as per your selection criterion
Log.d("TAG", "CEK 2 : " + viewable);
}
});
}
You may have to call notifyDataSetChanged() after changing the value of viewable.
onBindViewHolder will be called when you notify your data set.
So you need to save the viewable in mListChatting. When you click the button, change the viewable in the mListChatting.
And then, change the code in onBindViewHolder
holder.mFormBookingan.setVisibility(item.getViewable() ? View.VISIBLE : View.GONE);
On refresh android will destroy the view and create new view with new adapter data. So you have to track the current state (visibility) of mFormBookingan. You can use a simple visibility list. When mFormBookingan state (visibility) change update it in visibility list so that whenever the list is refreshed, you can use it to check and set the last state (visibility) of your mFormBookingan. Here is an example
private ArrayList<Boolean> isVisible;
public MyAdapter(ArrayList<Boolean> isVisible){
// initial state list of mFormBookingan for each row of list
this.isVisible = isVisible;
}
public void onBindViewHolder(final MyViewHolder holder, final int position) {
if (isVisible.get(position)) {
holder.mFormBookingan.setVisibility(View.VISIBLE);
}else {
holder.mFormBookingan.setVisibility(View.GONE);
}
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (holder.mFormBookingan.getVisibility() == View.GONE){
holder.mFormBookingan.setVisibility(View.VISIBLE);
isVisible.set(position, true);
}else {
holder.mFormBookingan.setVisibility(View.GONE);
isVisible.set(position, false);
}
}
});
}
when you click mSendBooking the mFormBookingan visibility will change and it will remain same after sending new item to recyclerview.

Mortar: How-to use Presenter for List Item/Adapter

I using a List with Custom Adapter with ViewHolder and Item Views with Buttons.
I want to handle some stuff by clicking the Buttons in a Presenter.
How can i connect a Presenter with these Item Views?
You can use rx-android to observe AdapterView's click events the following way. It combines fine with MVP pattern used in Mortar.
At first dependencies:
compile 'io.reactivex:rxjava:1.0.4'
compile 'io.reactivex:rxandroid:0.24.0'
Then create observeClicks method in your view class.
public Observable<OnItemClickEvent> observeClicks() {
return WidgetObservable.itemClicks(adapterView);
}
Subscribe to events in your Presenter's onLoad:
private Subscription clicks;
#Override
protected void onLoad() {
super.onLoad();
clicks = getView().observeClicks().subscribe(
new Action1<OnItemClickEvent>() {
#Override
public void call(OnItemClickEvent event) {
// handle click events
}
}
);
}
protected void onDestroy() {
// unsubscribe from events
clicks.unsubscribe();
}
Also you can do mapping OnItemClickEvent to your data inside view already and observe it instead of raw events.
public Observable<YourDataClass> observeClicks() {
return WidgetObservable.itemClicks(adapterView).
map(new Func1<OnItemClickEvent, YourDataClass>() {
#Override
public YourDataClass call(OnItemClickEvent onItemClickEvent) {
YourDataClass item = adapter.getItem(onItemClickEvent.position());
return item;
}
});
}
Hope this comes in handy. At least I'm doing this that way, but certainly it is not the only solution.
ListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Handle your stuff here.
});
Something like this? Use the position to get the current item out of your List.
Buttons :
// In the adapter
Button butt = (Button) rowView.findViewById(R.id.yourbutton);
butt.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
//Button Action.
}
}

Categories

Resources