Single and Double Tap on recycleview - java

I have a problem with my code, when i do a single or double tap on item both onDoubleTap and onSingleTapConfirmed are actived while i dont have problem with onLongClick.
In my activity:
mRecyclerView.addOnItemTouchListener(new RecyclerTouchListener(getContext(), mRecyclerView, new RecyclerTouchListener.ClickListener() {
#Override
public void onSingleTapConfirmed(View view, int position) {}
#Override
public void onDoubleTap(View view, int position){}
#Override
public void onLongClick(View view, int position) {}
}));
In my custom listener class:
public class RecyclerTouchListener implements recyclerView.OnItemTouchListener{
private GestureDetector gestureDetector;
private ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
#Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onSingleTapConfirmed(child, rv.getChildPosition(child));
}
return false;
}
public interface ClickListener {
void onSingleTapConfirmed(View view, int position);
void onDoubleTap(View view, int position);
void onLongClick(View view, int position);
}}

add this listener as OnDoubleClickListener.java:
public abstract class OnDoubleClickListener implements View.OnClickListener {
private final int doubleClickTimeout;
private Handler handler;
private long firstClickTime;
public OnDoubleClickListener() {
doubleClickTimeout = ViewConfiguration.getDoubleTapTimeout();
firstClickTime = 0L;
handler = new Handler(Looper.getMainLooper());
}
#Override
public void onClick(final View v) {
long now = System.currentTimeMillis();
if (now - firstClickTime < doubleClickTimeout) {
handler.removeCallbacksAndMessages(null);
firstClickTime = 0L;
onDoubleClick(v);
} else {
firstClickTime = now;
handler.postDelayed(new Runnable() {
#Override
public void run() {
onSingleClick(v);
firstClickTime = 0L;
}
}, doubleClickTimeout);
}
}
public abstract void onDoubleClick(View v);
public abstract void onSingleClick(View v);
public void reset() {
handler.removeCallbacksAndMessages(null);
}
}
and then add ItemClickSupport.java
public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnDoubleClickListener mOnDoubleClickListener = new OnDoubleClickListener() {
#Override
public void onDoubleClick(View v) {
if (mOnItemClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemDoubleClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
#Override
public void onSingleClick(View v) {
if (mOnItemClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
#Override
public void onChildViewAttachedToWindow(View view) {
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnDoubleClickListener);
}
}
#Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}
public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
return this;
}
private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(mAttachListener);
view.setTag(R.id.item_click_support, null);
}
public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View v);
void onItemDoubleClicked(RecyclerView recyclerView, int position, View v);
}
}
and use it :
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(),
2, GridLayoutManager.VERTICAL, false));
// Make sure your recyler view adapter implements getItemAt(position), which return the item from the dataset placed at position
// in this case I use getProductId() from my POJO Product class
ItemClickSupport.addTo(mRecyclerView)
.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
Log.d("ITEM CLICK", "Item single clicked " + mRecyclerViewAdapter.getItemAt(position).getProductId());
}
#Override
public void onItemDoubleClicked(RecyclerView recyclerView, int position, View v) {
Log.d("ITEM CLICK", "Item double clicked " + mRecyclerViewAdapter.getItemAt(position).getProductId());
}
});
source
or check this gist

Related

How to add OnitemClickListener in ArrayList without ListView

I want to make a dashboard in android studio.I use two xml for making dashboard main_activity and list_item activity.In the coding session i used model class adapter and also main class.
public class MainActivity extends AppCompatActivity {
ArrayList<DashModel> dashModelArrayList;
DashAdapter dashAdapter;
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.rv1);
dashModelArrayList = new ArrayList<>();
String heads[] = {"Jobs", "My Profile", "Messages", "Applied Jobs", "Resume", "Settings"};
String subs[] = {"12 new jobs found", "75% complete", "2 new messages", "3 applies jobs", "Edit resume", "Set preferences"};
int images[] = {R.drawable.find_jobs, R.drawable.profile, R.drawable.messages, R.drawable.applied_jobs,
R.drawable.resume, R.drawable.settings};
for (int count = 0; count < heads.length; count++) {
DashModel dashModel = new DashModel();
dashModel.setHead(heads[count]);
dashModel.setSub(subs[count]);
dashModel.setImage(images[count]);
dashModelArrayList.add(dashModel);
//this should be retrieved in our adapter
}
recyclerView.setLayoutManager(new GridLayoutManager(getApplicationContext(), 2));
dashAdapter = new DashAdapter(dashModelArrayList);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(dashAdapter);
}}
Adapter class :
public class DashAdapter extends RecyclerView.Adapter<DashAdapter.ViewHolder> {
ArrayList<DashModel> dashModelArrayList;
public DashAdapter(ArrayList<DashModel> dashModelArrayList) {
this.dashModelArrayList = dashModelArrayList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String ret_head = dashModelArrayList.get(position).getHead();
holder.setheader(ret_head);
String ret_sub = dashModelArrayList.get(position).getSub();
holder.set_sub(ret_sub);
int ret_image = dashModelArrayList.get(position).getImage();
holder.set_image(ret_image);
}
#Override
public int getItemCount() {
return dashModelArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView header,sub_header;
ImageView images;
View myView;
public ViewHolder(View itemView) {
super(itemView);
myView = itemView;
}
public void setheader(String h)
{
header = myView.findViewById(R.id.header);
header.setText(h);
}
public void set_sub(String s)
{
sub_header = myView.findViewById(R.id.sub_header);
sub_header.setText(s);
}
public void set_image(int i)
{
images = myView.findViewById(R.id.dash_image);
images.setImageResource(i);
}
}}
How can i add onItemclickListener here?
I expect and want to add OnItemclickListener in the icon but i can't and don't know how to add.
To create a onClickListener for RecyclerView you have to create a class which implements the RecyclerView.OnItemTouchListener
import android.support.v7.widget.*;
import android.view.*;
import android.content.*;
public class RecyclerViewTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ClickListener clickListener;
public RecyclerViewTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
public interface ClickListener{
public void onClick(View view,int position);
public void onLongClick(View view,int position);
}
}
After that you can attach it to your RecyclerView to listen for clicks.
recyclerView.addOnItemTouchListener(new RecyclerViewTouchListener(getActivity(), recyclerView, new RecyclerViewTouchListener.ClickListener(){
#Override
public void onClick(View view, int position)
{
// TODO: Implement this method
}
#Override
public void onLongClick(View view, int position)
{
// TODO: Implement this method
}
}));

wrong recyclerview item position

my recyclerview is great in scrolling but when it contains more than two items and click on last item or the one before it gives me the wrong position this is
and throws a NullPointerException this is my whole code from adapter to the listener.
my code :
public class ListAdapter extends RecyclerView.Adapter<ViewHolder> {
private List<ItemView> items;
private Context context;
public ListAdapter(List<ItemView> items, Context context) {
this.items = items;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_style, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ItemView i = items.get(position);
ViewHolder.setHeadText(i.getHead());
ViewHolder.setScoreText(i.getContent());
}
#Override
public int getItemCount() {
return items.size();
}
}
class ViewHolder extends RecyclerView.ViewHolder {
private RecyclerViewOnTouchItemListener.ClickListener clickListener;
private static TextView headText, urlText;
private ConstraintLayout itemLayout;
public ViewHolder(View itemView) {
super(itemView);
headText = (TextView) itemView.findViewById(R.id.list_item_header);
urlText = (TextView) itemView.findViewById(R.id.list_item_content);
itemLayout = (ConstraintLayout) itemView.findViewById(R.id.item_list);
// itemLayout.setOnClickListener(this);
}
public static void setHeadText(String headText) {
ViewHolder.headText.setText(headText);
}
public static void setScoreText(String scoreText) {
ViewHolder.urlText.setText(scoreText);
}
public static String getHeadText(){return headText.getText().toString();}
public static String getUrlText(){return urlText.getText().toString();}
}
class RecyclerViewOnTouchItemListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ClickListener clickListener;
public RecyclerViewOnTouchItemListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildAdapterPosition(child));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) { }
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
interface ClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);
}
}
and this is the activity that holds the recyclerview :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_url_list);
context = getApplicationContext();
database = new DatabaseHelper(context);
listOfUrl = (RecyclerView) findViewById(R.id.url_list);
find = (Button) findViewById(R.id.findBtn);
cancel = (Button) findViewById(R.id.cancelBtn);
makeItPopUp();
listOfUrl.setLayoutManager(new LinearLayoutManager(this));
listOfUrl.setHasFixedSize(true);
listOfUrl.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
adapter = new ListAdapter(fillList(), context);
listOfUrl.setAdapter(adapter);
adapter.notifyDataSetChanged();
selectedItems = new ArrayList<Boolean>(Arrays.asList(new Boolean[listOfUrl.getAdapter().getItemCount()]));
Collections.fill(selectedItems, Boolean.FALSE);
listOfUrl.addOnItemTouchListener(
new RecyclerViewOnTouchItemListener(this, listOfUrl
, new RecyclerViewOnTouchItemListener.ClickListener() {
#Override
public void onClick(View view, int position) {
if (selectedItems.get(position))
setItemSelectedState(false, position, Color.WHITE);
else
setItemSelectedState(true, position, Color.LTGRAY);
}
#Override
public void onLongClick(View view, int position) {}
private void setItemSelectedState(boolean isSelected, int position, int color) {
try {
listOfUrl.getChildAt(position).setBackgroundColor(color);
selectedItems.add(position, isSelected);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
})
);
find.setOnClickListener(this);
cancel.setOnClickListener(this); }
any on can tell me what i did wrong.
Simple solution, create interface class:
public interface ListListener {
void onClick(int pos);
void onLongClick(int pos);
}
Adjust the content of your RecyclerViewAdapter class:
public class ListAdapter extends RecyclerView.Adapter<ViewHolder> {
private ListListener listener;
private List<ItemView> items;
private Context context;
public ListAdapter(List<ItemView> items, Context context) {
this.items = items;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_style, parent, false);
return new ViewHolder(view);
}
public ItemView getItem(int pos) {
return items.get(pos);
}
public void setListener(ListListener listener) {
this.listener = listener;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ItemView i = items.get(position);
holder.setHeadText(i.getHead());
holder.setScoreText(i.getContent());
holder.itemLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int pos = holder.getAdapterPosition();
if (listener != null && pos != RecyclerView.NO_POSITION) {
listener.onClick(pos);
}
}
});
holder.itemLayout.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
int pos = holder.getAdapterPosition();
if (pos != -1) {
if (listener != null) {
listener.onLongClick(getItem(pos));
}
}
return true;
}
});
}
And in your Activity class I edited some parts:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_url_list);
context = getApplicationContext();
database = new DatabaseHelper(context);
listOfUrl = (RecyclerView) findViewById(R.id.url_list);
find = (Button) findViewById(R.id.findBtn);
cancel = (Button) findViewById(R.id.cancelBtn);
makeItPopUp();
listOfUrl.setLayoutManager(new LinearLayoutManager(this));
listOfUrl.setHasFixedSize(true);
listOfUrl.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
adapter = new ListAdapter(fillList(), context);
adapter.setListener(new SelectCountryDialogListener() {
#Override
public void onClick(int pos) {
ItemView item = adapter.getItem(pos);
}
#Override
public void onLongClick(int pos) {
ItemView item = adapter.getItem(pos);
}
});
listOfUrl.setAdapter(adapter);
selectedItems = new ArrayList<Boolean>(Arrays.asList(new Boolean[listOfUrl.getAdapter().getItemCount()]));
Collections.fill(selectedItems, Boolean.FALSE);
find.setOnClickListener(this);
cancel.setOnClickListener(this);
}
I'm pretty sure, that now it is very easy for you. Just to implement the functionality in onClick and onLongClick methods.

Add item on RecycleView Android

I'm trying to add an item on RecycleView like this:
I have an object called Image
public class Image{
public String name;
public String url;
}
When I click on the button to add a new item, my code is like this:
#Override
public void addItemOnList(String url) {
adapter.addItem(new ImageObject("aaaaaa", R.drawable.close_button));
}
That is my method which inserts on the list.
public void addItem(ImageObject imageObject) {
itemList.add(imageObject);
notifyDataSetChanged();
}
My problem is when I click for the first time in additem my onBindViewHolder doesn't iterate all the list but when I check in debug mod my getItemCount is correct! So If I try to add an item after the first time all work well.
MainActivity
public class MainActivity extends AppCompatActivity implements RecyclerViewClickListener, OnStartDragListener {
private RecyclerViewAdapter adapter;
private ArrayList<ImageObject> listViewItems;
private RecyclerView recyclerView;
private ItemTouchHelper itemTouchHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
StaggeredGridLayoutManager staggeredLayoutManager = new StaggeredGridLayoutManager(3, 1);
recyclerView.setLayoutManager(staggeredLayoutManager);
List<ImageObject> staggered = getListItemData();
adapter = new RecyclerViewAdapter(this, staggered);
recyclerView.setAdapter(adapter);
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
private List<ImageObject> getListItemData() {
listViewItems = new ArrayList<ImageObject>();
listViewItems.add(new ImageObject("Alkane", R.drawable.one));
listViewItems.add(new ImageObject("Ethane", R.drawable.two));
listViewItems.add(new ImageObject("Alkyne", R.drawable.three));
listViewItems.add(new ImageObject("Benzene", R.drawable.four));
listViewItems.add(new ImageObject("Alkane", R.drawable.one));
listViewItems.add(new ImageObject("Ethane", R.drawable.two));
listViewItems.add(new ImageObject("Alkyne", R.drawable.three));
listViewItems.add(new ImageObject("Benzene", R.drawable.four));
listViewItems.add(new ImageObject("Alkane", R.drawable.one));
listViewItems.add(new ImageObject("Ethane", R.drawable.two));
listViewItems.add(new ImageObject("Alkyne", R.drawable.three));
listViewItems.add(new ImageObject("Benzene", R.drawable.four));
return listViewItems;
}
#Override
public void addButtonClicked() {
FragmentManager fm = getSupportFragmentManager();
AlertFragment.newInstance(this).show(fm, "dialog");
}
#Override
public void addItemOnList(String url) {
adapter.addItem(new ImageObject("aaaaaa", R.drawable.close_button));
}
#Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
itemTouchHelper.startDrag(viewHolder);
}
}
My Adapter
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolders> implements ItemTouchHelperAdapter {
private List<ImageObject> itemList;
private MainActivity mainActivity;
private RecyclerViewClickListener recycleListener;
private OnStartDragListener dragStartListener;
public RecyclerViewAdapter(MainActivity mainActivity, List<ImageObject> itemList) {
this.itemList = itemList;
this.mainActivity = mainActivity;
this.recycleListener = mainActivity;
this.dragStartListener = mainActivity;
}
#Override
public ViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView;
switch (viewType) {
case 1:
layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.add_item_list, null);
break;
default:
layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, null);
break;
}
return new ViewHolders(layoutView);
}
#Override
public void onBindViewHolder(final ViewHolders holder, final int position) {
switch (holder.getItemViewType()) {
case 1:
configureViewHolderAddItem(holder, position);
break;
case 0:
configureDefaultViewHolder(holder, position);
break;
}
}
private void configureViewHolderAddItem(final ViewHolders holder, final int position) {
holder.addItemLayout = holder.itemView.findViewById(R.id.add_item_layout);
holder.addItemLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
recycleListener.addButtonClicked();
}
});
}
private void configureDefaultViewHolder(final ViewHolders holder, final int position) {
Log.e("test", "position - " + position);
Log.e("test", "name - " + itemList.get(position).getName());
holder.itemLayout = holder.itemView.findViewById(R.id.main_layout);
holder.removeItemButton = holder.itemView.findViewById(R.id.remove_item_button);
holder.itemLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
itemList.remove(holder.getLayoutPosition());
notifyItemRemoved(holder.getLayoutPosition());
notifyItemRangeChanged(holder.getLayoutPosition(), itemList.size());
}
});
holder.itemLayout.setBackgroundResource(itemList.get(position).getPhoto());
holder.itemLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
dragStartListener.onStartDrag(holder);
}
return false;
}
});
//resizeTheFirstPosition(holder, position);
}
private void resizeTheFirstPosition(ViewHolders holder, int position) {
if (position == 0) {
int dimensionInDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
200, mainActivity.getResources().getDisplayMetrics());
holder.itemLayout.getLayoutParams().height = dimensionInDp;
holder.itemLayout.getLayoutParams().width = dimensionInDp;
holder.itemLayout.requestLayout();
}
}
public void addItem(ImageObject imageObject) {
itemList.add(imageObject);
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
return position == itemList.size() - 1 ? 1 : 0;
}
#Override
public int getItemCount() {
return this.itemList.size();
}
#Override
public boolean onItemMove(int fromPosition, int toPosition) {
Collections.swap(itemList, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
return true;
}
#Override
public void onItemDismiss(int position) {
itemList.remove(position);
notifyItemRemoved(position);
}
public class ViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener,
ItemTouchHelperViewHolder {
private ImageView removeItemButton;
private ImageView addItemButton;
private FrameLayout addItemLayout;
private RelativeLayout itemLayout;
public ViewHolders(View itemView) {
super(itemView);
}
#Override
public void onClick(View view) {
itemList.remove(getLayoutPosition());
//notifyItemRemoved(getLayoutPosition());
notifyItemRangeChanged(getLayoutPosition(), itemList.size());
Toast.makeText(mainActivity, "Removed item- " + getLayoutPosition(), Toast.LENGTH_SHORT).show();
}
#Override
public void onItemSelected() {
itemView.setBackgroundColor(Color.LTGRAY);
}
#Override
public void onItemClear() {
itemView.setBackgroundColor(0);
}
}
Finally, I fixed this. I don't know why but I change how I insert on the list
Old code:
public void addItem(ImageObject imageObject) {
itemList.add(imageObject);
notifyDataSetChanged();
}
New code:
public void addItem(ImageObject imageObject) {
itemList.add(itemList.size() - 1, imageObject);
notifyDataSetChanged();
}

OnItemClickListener for RecyclerView in ViewPager

I am trying to open a url link when I click on a list item in a recyclerview but I keep getting a NullPointerException. I am using a ViewPager, I don't know if this is the cause of the exception, maybe I'm doing something wrong. Please check out my code and logcat below.
This is my adapter:
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.NewsHolder> {
private ArrayList<News> mNews = new ArrayList<>();
private static ClickListener clickListener;
public NewsAdapter(ArrayList<News> news) {
mNews = news;
}
private static String timeConverter(String inputTime) {
long startTime = 0;
SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
simpleDate.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
Date date = simpleDate.parse(inputTime);
startTime = date.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
long currentTime = System.currentTimeMillis();
long end = currentTime - startTime;
long seconds = TimeUnit.MILLISECONDS.toSeconds(end);
long minutes = TimeUnit.SECONDS.toMinutes(seconds);
long hours = TimeUnit.MINUTES.toHours(minutes);
if (minutes > 59) {
return hours + "h";
}else if (seconds > 59) {
return minutes + "m";
}else {
return seconds + "s";
}
}
#Override
public NewsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_view, parent, false);
return new NewsHolder(view);
}
#Override
public void onBindViewHolder(NewsHolder holder, int position) {
String imagePath = mNews.get(position).getImageUrl();
Picasso.with(holder.mImageView.getContext()).load(imagePath).into(holder.mImageView);
holder.mNewsTextView.setText(mNews.get(position).getNews());
holder.mTimeStampTextView.setText(timeConverter(mNews.get(position).getTime()));
}
#Override
public int getItemCount() {
return mNews.size();
}
// NewsHolder class that extends the ViewHolder
public static class NewsHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ImageView mImageView;
private TextView mNewsTextView;
private TextView mTimeStampTextView;
// Setting the views
public NewsHolder(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.simple_imageView);
mNewsTextView = (TextView) itemView.findViewById(R.id.news_tv);
mTimeStampTextView = (TextView) itemView.findViewById(R.id.time_tv);
}
#Override
public void onClick(View view) {
clickListener.onItemClick(getAdapterPosition(), view);
}
}
public void setOnItemClickListener(ClickListener listener) {
NewsAdapter.clickListener = listener;
}
public interface ClickListener {
void onItemClick(int position, View v);
}
}
This is one of my ViewPager fragments:
public class TechFragment extends Fragment {
private SwipeRefreshLayout mSwipeRefreshLayout;
private TextView mErrorMessage;
private NewsAdapter mNewsAdapter;
ArrayList<News> news;
NetworkInfo info;
// The Loader takes in a bundle
Bundle sourceBundle = new Bundle();
private final String LOG_TAG = MainActivity.class.getSimpleName();
private static final String TECH_NEWS_QUERY_URL = "query";
private static final String TECH_NEWS_SOURCE = "techcrunch";
private static final String TECH_SOURCE_CATEGORY = "latest";
private static final int TECH_NEWS_LOADER = 22;
private RecyclerView mRecyclerView;
public TechFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_news, container, false);
mErrorMessage = (TextView) view.findViewById(R.id.tv_error_message);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view_main);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefresh);
getActivity().getSupportLoaderManager().initLoader(TECH_NEWS_LOADER, sourceBundle, new NewsDataLoader());
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Log.v(LOG_TAG, "Refreshing");
restartLoader();
mSwipeRefreshLayout.setColorSchemeResources(
R.color.colorPrimary,
R.color.colorPrimaryDark);
}
});
return view;
}
private boolean isConnected() {
ConnectivityManager cm = (ConnectivityManager) getActivity()
.getSystemService(CONNECTIVITY_SERVICE);
info = cm.getActiveNetworkInfo();
return info != null && info.isConnectedOrConnecting();
}
private int anyRandomInt(Random random) {
return random.nextInt();
}
private void restartLoader() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
URL techNewsUrl = NetworkUtils.buildUrl(TECH_NEWS_SOURCE, TECH_SOURCE_CATEGORY);
sourceBundle.putString(TECH_NEWS_QUERY_URL, techNewsUrl.toString());
Random random = new Random();
int uniqueId = anyRandomInt(random); //Generates a new ID for each loader call;
LoaderManager loaderManager = getActivity().getSupportLoaderManager();
if (loaderManager.getLoader(TECH_NEWS_LOADER) == null) {
loaderManager.initLoader(uniqueId, sourceBundle, new NewsDataLoader());
} else {
loaderManager.restartLoader(TECH_NEWS_LOADER, sourceBundle, new
NewsDataLoader());
}
}
}, 5000);
mSwipeRefreshLayout.setRefreshing(false);
Log.v(LOG_TAG, "Finished refreshing");
}
private void showErrorScreen() {
mErrorMessage.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.INVISIBLE);
mErrorMessage.setText(getString(R.string.internet_error));
}
public class NewsDataLoader implements LoaderManager.LoaderCallbacks<ArrayList<News>> {
#Override
public Loader<ArrayList<News>> onCreateLoader(int id, final Bundle args) {
if (isConnected()) {
mErrorMessage.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
return new AsyncTaskLoader<ArrayList<News>>(getActivity()) {
ArrayList<News> mNewsData;
#Override
protected void onStartLoading() {
super.onStartLoading();
if (mNewsData != null) {
deliverResult(mNewsData);
} else {
forceLoad();
mSwipeRefreshLayout.setRefreshing(true);
}
}
#Override
public ArrayList<News> loadInBackground() {
try {
ArrayList<News> news = NetworkUtils.parseJSON(TECH_NEWS_SOURCE, TECH_SOURCE_CATEGORY);
return news;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public void deliverResult(ArrayList<News> data) {
mNewsData = data;
super.deliverResult(data);
}
};
} else {
showErrorScreen();
return null;
}
}
#Override
public void onLoadFinished(Loader<ArrayList<News>> loader, final ArrayList<News> data) {
mSwipeRefreshLayout.setRefreshing(false);
if (null == data) {
showErrorScreen();
} else {
mErrorMessage.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
if (news != null) {
news.clear();
news.addAll(data);
mNewsAdapter = new NewsAdapter(news);
mRecyclerView.setAdapter(mNewsAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
mNewsAdapter.notifyDataSetChanged();
} else {
news = data;
}
}
mNewsAdapter.setOnItemClickListener(new NewsAdapter.ClickListener() {
#Override
public void onItemClick(int position, View v) {
News currentNews = news.get(position);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(currentNews.getUrl()));
if (intent.resolveActivity(getActivity().getPackageManager()) != null){
startActivity(intent);
}
}
});
}
#Override
public void onLoaderReset(Loader<ArrayList<News>> loader) {
}
}
}
And this is my error:
06-13 12:11:38.667 3890-3890/com.ire.blogbot E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ire.blogbot, PID: 3890
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.ire.blogbot.adapter.NewsAdapter.setOnItemClickListener(com.ire.blogbot.adapter.NewsAdapter$ClickListener)' on a null object reference
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader.onLoadFinished(TechFragment.java:192)
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader.onLoadFinished(TechFragment.java:131)
at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:476)
at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:444)
at android.support.v4.content.Loader.deliverResult(Loader.java:126)
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader$1.deliverResult(TechFragment.java:164)
at com.ire.blogbot.fragments.TechFragment$NewsDataLoader$1.deliverResult(TechFragment.java:137)
at android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:252)
at android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:80)
at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:485)
at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:502)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Try this code, it is working
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
#Override public void onItemClick(View view, int position) {
// on click
}
})
);
RecyclerItemClickListener Class
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}}
Move
mNewsAdapter.setOnItemClickListener(new NewsAdapter.ClickListener() {
#Override
public void onItemClick(int position, View v) {
News currentNews = news.get(position);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(currentNews.getUrl()));
if (intent.resolveActivity(getActivity().getPackageManager()) != null){
startActivity(intent);
}
}
});
after
mNewsAdapter = new NewsAdapter(news);

Overriding getContextMenuInfo() from custom Adapter

I am building a list that had to be able to reorder the item's position.
Fortunately for me, I've found an external library which has exactly what I needed.
Unfortunately, I could not implement a delete item action using onContextItemSelected() because menuInfo keeps always returning null, so I cannot read the position of selected item I wish to delete.
This user blog post gave a solution by overriding getContextMenuInfo().
If item.getMenuInfo() is null in onContextItemSelected(MenuItem item) method, I guess you are using custom ListView or GridView instead of android default ones. In such case, your custom View is not implementing getContextMenuInfo() method. Don’t worry we can fix that if you have its source. Open the view file and override the method getContextMenuInfo().
I have tried this in many ways, but it seems I am doing things wrong.
Is this the only solution or am I missing something?
Activity
public class SurveyAdd extends AppCompatActivity {
private ArrayList<Pair<Long, String>> mItemArray = new ArrayList<>();
private DragListView mDragListView;
ItemAdapter listAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_survey_add);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDragListView = (DragListView) findViewById(R.id.surveyadd_list);
mDragListView.getRecyclerView().setVerticalScrollBarEnabled(true);
mDragListView.setDragListListener(new DragListView.DragListListener() {
#Override
public void onItemDragStarted(int position) {
}
#Override
public void onItemDragEnded(int fromPosition, int toPosition) {
if (fromPosition != toPosition) {
setSurveyChange(true);
}
}
});
mDragListView.setCanDragHorizontally(false);
mDragListView.setCustomDragItem(new MyDragItem(context, R.layout.item_survey_add));
mDragListView.setLayoutManager(new LinearLayoutManager(context));
mDragListView.setLayoutManager(new LinearLayoutManager(context));
ItemAdapter listAdapter = new ItemAdapter(mItemArray, R.layout.item_survey_add, R.id.item_add_image_button, false);
mDragListView.setAdapter(listAdapter, true);
registerForContextMenu(mDragListView);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_survey_add_item, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.surveyadd_action_delete:
if (item.getMenuInfo() == null) {
Toast.makeText(SurveyAdd.this, "NULL", Toast.LENGTH_SHORT).show();
}
int position = info.position; // CAN'T USE THIS, ALWAYS THROWS NULLPOINTEREXCEPTION
Toast.makeText(SurveyAdd.this, "" + position, Toast.LENGTH_SHORT).show();
return true;
}
}
}
// The activity was simplified for posting
ItemAdapter
imported and edited class
public class ItemAdapter extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder> {
private int mLayoutId;
private int mGrabHandleId;
public ItemAdapter(ArrayList<Pair<Long, String>> list, int layoutId, int grabHandleId, boolean dragOnLongPress) {
super(dragOnLongPress);
mLayoutId = layoutId;
mGrabHandleId = grabHandleId;
setHasStableIds(true);
setItemList(list);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
String text = mItemList.get(position).second;
String[] separated = text.split("::");
holder.mText.setText(separated[1]);
holder.itemView.setTag(text);
}
#Override
public long getItemId(int position) {
return mItemList.get(position).first;
}
public class ViewHolder extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder>.ViewHolder {
public TextView mText;
public ImageView mIcon;
public ViewHolder(final View itemView) {
super(itemView, mGrabHandleId);
mText = (TextView) itemView.findViewById(R.id.item_add_question);
mIcon = (ImageView) itemView.findViewById(mGrabHandleId);
}
#Override
public void onItemClicked(View view) {
}
#Override
public boolean onItemLongClicked(View view) {
return false;
}
}
}
DragListView
imported and locked class
public class DragListView extends FrameLayout {
public interface DragListListener {
void onItemDragStarted(int position);
void onItemDragEnded(int fromPosition, int toPosition);
}
private DragItemRecyclerView mRecyclerView;
private DragListListener mDragListListener;
private DragItem mDragItem;
private boolean mDragEnabled = true;
private float mTouchX;
private float mTouchY;
public DragListView(Context context) {
super(context);
}
public DragListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mDragItem = new DragItem(getContext());
mRecyclerView = createRecyclerView();
mRecyclerView.setDragItem(mDragItem);
addView(mRecyclerView);
addView(mDragItem.getDragItemView());
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean retValue = handleTouchEvent(event);
return retValue || super.onInterceptTouchEvent(event);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean retValue = handleTouchEvent(event);
return retValue || super.onTouchEvent(event);
}
private boolean handleTouchEvent(MotionEvent event) {
mTouchX = event.getX();
mTouchY = event.getY();
if (isDragging()) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mRecyclerView.onDragging(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mRecyclerView.onDragEnded();
break;
}
return true;
}
return false;
}
private DragItemRecyclerView createRecyclerView() {
final DragItemRecyclerView recyclerView = (DragItemRecyclerView) LayoutInflater.from(getContext()).inflate(R.layout.drag_item_recycler_view, this, false);
recyclerView.setMotionEventSplittingEnabled(false);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setVerticalScrollBarEnabled(false);
recyclerView.setHorizontalScrollBarEnabled(false);
recyclerView.setDragItemListener(new DragItemRecyclerView.DragItemListener() {
private int mDragStartPosition;
#Override
public void onDragStarted(int itemPosition, float x, float y) {
getParent().requestDisallowInterceptTouchEvent(true);
mDragStartPosition = itemPosition;
if (mDragListListener != null) {
mDragListListener.onItemDragStarted(itemPosition);
}
}
#Override
public void onDragging(int itemPosition, float x, float y) {
}
#Override
public void onDragEnded(int newItemPosition) {
if (mDragListListener != null) {
mDragListListener.onItemDragEnded(mDragStartPosition, newItemPosition);
}
}
});
return recyclerView;
}
public RecyclerView getRecyclerView() {
return mRecyclerView;
}
public DragItemAdapter getAdapter() {
if (mRecyclerView != null) {
return (DragItemAdapter) mRecyclerView.getAdapter();
}
return null;
}
public void setAdapter(DragItemAdapter adapter, boolean hasFixedItemSize) {
mRecyclerView.setHasFixedSize(hasFixedItemSize);
mRecyclerView.setAdapter(adapter);
adapter.setDragEnabled(mDragEnabled);
adapter.setDragStartedListener(new DragItemAdapter.DragStartedListener() {
#Override
public void onDragStarted(View itemView, long itemId) {
mRecyclerView.onDragStarted(itemView, itemId, mTouchX, mTouchY);
}
});
}
public void setLayoutManager(RecyclerView.LayoutManager layout) {
mRecyclerView.setLayoutManager(layout);
}
public void setDragListListener(DragListListener listener) {
mDragListListener = listener;
}
public boolean isDragEnabled() {
return mDragEnabled;
}
public void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
if (mRecyclerView.getAdapter() != null) {
((DragItemAdapter) mRecyclerView.getAdapter()).setDragEnabled(mDragEnabled);
}
}
public void setCustomDragItem(DragItem dragItem) {
removeViewAt(1);
DragItem newDragItem;
if (dragItem != null) {
newDragItem = dragItem;
} else {
newDragItem = new DragItem(getContext());
}
newDragItem.setCanDragHorizontally(mDragItem.canDragHorizontally());
newDragItem.setSnapToTouch(mDragItem.isSnapToTouch());
mDragItem = newDragItem;
mRecyclerView.setDragItem(mDragItem);
addView(mDragItem.getDragItemView());
}
public boolean isDragging() {
return mRecyclerView.isDragging();
}
public void setCanDragHorizontally(boolean canDragHorizontally) {
mDragItem.setCanDragHorizontally(canDragHorizontally);
}
public void setSnapDragItemToTouch(boolean snapToTouch) {
mDragItem.setSnapToTouch(snapToTouch);
}
public void setCanNotDragAboveTopItem(boolean canNotDragAboveTop) {
mRecyclerView.setCanNotDragAboveTopItem(canNotDragAboveTop);
}
public void setScrollingEnabled(boolean scrollingEnabled) {
mRecyclerView.setScrollingEnabled(scrollingEnabled);
}
}
This is an old post but i figured it out using that same draglistview.
Im using Xamarin but it's close enough to the same. Just type the C# in Java as necessary:
protected override IContextMenuContextMenuInfo ContextMenuInfo
{
get
{
IContextMenuContextMenuInfo menuInfo = base.ContextMenuInfo;
if (menuInfo == null)
{
IListAdapter adapter = Adapter;
int pos = GetPositionForView(selectedView);
menuInfo = new AdapterContextMenuInfo(selectedView, pos, adapter.GetItemId(pos));
}
return menuInfo;
}
}
public void OnLongPress(MotionEvent e){
int position = PointToPosition(mDownX, mDownY);
int itemNum = position - FirstVisiblePosition;
selectedView = GetChildAt(itemNum); //class variable
...
}

Categories