I use a GestureListener on an image to detect a Double Tap.
holder.image.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return holder.myDoubleTapDetector.onTouchEvent(event);
}
});
And I use the library Zoomy to make the images zoomable.
Zoomy.Builder builder = new Zoomy.Builder(mActivity).target(holder.image);
builder.register();
Both work perfectly fine for them alone.
But adding both at the same time does not work! Only the one that was added last works.
How can I have both of them working?
Zoomy provides a solution for that:
Because Zoomy works by attaching a View.OnTouchListener to the registered View, View.OnClickListener can not be set along with Zoomy, so a TapListener, LongPressListener and DoubleTapListener are provided to ensure the View still can listen for gestures. A ZoomListener is also provided if you are interested in zoom events.
In Code:
Zoomy.Builder builder = new Zoomy.Builder(this)
.target(mZoomableView)
.tapListener(new TapListener() {
#Override
public void onTap(View v) {
//View tapped, do stuff
}
})
.longPressListener(new LongPressListener() {
#Override
public void onLongPress(View v) {
//View long pressed, do stuff
}
}).doubleTapListener(new DoubleTapListener() {
#Override
public void onDoubleTap(View v) {
//View double tapped, do stuff
}
})
.zoomListener(new ZoomListener() {
#Override
public void onViewStartedZooming(View view) {
//View started zooming
}
#Override
public void onViewEndedZooming(View view) {
//View ended zooming
}
});
Related
I have a messaging app similar to whatsapp where there are messages videos and images in the chat activity. Now I want to implement a double tap like feature on this but the problem is I also have a onclicklistner attached to my image and video frame that opens up a fullscreenactivity showing the image in fullscreen or playing the video in fullscreen. So on double tap instead of liking the picture or video it simply opens the video or image in the fullscreen mode. Since in messages I don't have a onclick listner attached double tap like works fine. Any ideas on how I can make the double tap like work in case of the videos or images. I am fairly new to android development using Java. So any help is appreciated.
HI, I think the approach to take depends on the future of your app, using LongClick is kinda good but what if you want to achieve a zoom like onLongClick?
What I did below is that I created a subclass that extends GestureDetector.SimpleOnGestureListener and then in my GestureTest class, I an ontouchListener and return the gesture instance created before, finally I parse the listener to the button that has to perform the clicks, it can be any View object.
Finally, I used the TextView I created to display/monitor my actions.
GestureDetector like below:
public class GestureTest extends AppCompatActivity{
private Button btn;
private TextView actions;
private GestureDetector mDetector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gesture_test);
btn = findViewById(R.id.btn);
actions = findViewById(R.id.action);
mDetector = new GestureDetector(this, new SampleGestureListener());
View.OnTouchListener touchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return mDetector.onTouchEvent(event);
}
};
btn.setOnTouchListener(touchListener);
}
public class SampleGestureListener extends GestureDetector.SimpleOnGestureListener{
#Override
public boolean onDown(MotionEvent event) {
Log.e("EVENT","BUTTON PRESSED DOWN, NOT YET RELEASED WILL TRIGGER ONLONG-PRESS");
// don't return false here or else none of the other
// gestures will work
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.e("EVENT", "SINGLE CLICK EVENT");
actions.setText("THIS CLICK IS FOR IMAGE OR VIDEO TO OPEN ?");
return true;
}
#Override
public void onLongPress(MotionEvent e) {
Log.e("EVENT", "LONG PRESSED");
actions.setText("THIS IS ZOOM LIKE NOT DOUBLE CLICK!!!");
}
#Override
public boolean onDoubleTap(MotionEvent e) {
Log.e("EVENT", "DOUBLE CLICKED HAPPENED");
actions.setText("THIS CLICK IS TO LIKE IMAGE OR VIDEO ?");
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.e("EVENT", "SCROLLING");
actions.setText("YOU\" Scrolling on many images...");
return true;
}
#Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
Log.e("EVENT", "FLINGED");
actions.setText("THIS IS TINDER FLING LIKE ?");
return true;
}
}
}
AND BELOW IS MY activity_gesture_test.xml FOR TESTING:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btn"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="100dp"/>
<TextView
android:id="#+id/action"
android:textSize="20dp"
android:textColor="#color/black"
app:layout_constraintTop_toBottomOf="#+id/btn"
android:layout_width="match_parent"
android:layout_height="100dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
GoodLuck Coding.
try this for double click:
int i = 0;
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
i++;
Handler handler = new Handler();
Runnable r = new Runnable() {
#Override
public void run() {
i = 0;
}
};
if (i == 1) {
//Single click
handler.postDelayed(r, 250);
} else if (i == 2) {
//Double click
i = 0;
ShowDailog();
}
}
});
and for click listener:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
It is generally accepted to use long tap instead of double click in android apps. Try this:
yourView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
//do Your stuff here
return true;
}
});
thanks for helping. I was trying to implement an add to favorite function in my recycler view, everything is working fine except for one thing. I am unable to commit the changed image button in my recycler view, every time I press the button, the post is added to the favorites and the image button turns yellow, but as soon as I move to some other fragment, the yellow button goes back to its initial stage. Can anyone of you help me on how can I make my button commit to the changes in recycler view. Below is my relevant code.
Initialization of buttons in holder class:
class UsersViewHolder1 extends RecyclerView.ViewHolder {
View mView;
private ImageButton mFavouritesBlack, mFavouritesYellow;
private GestureDetector mGestureDetector;
private Heart mHeart;
public UsersViewHolder1(View itemView) {
super(itemView);
mView = itemView;
mFavouritesBlack = mView.findViewById(R.id.ad_start_fav);
mFavouritesYellow = mView.findViewById(R.id.ad_start_fav1);
}
}
OnBindViewHOlder class(I omitted the irrelevant code):
protected void onBindViewHolder(#NonNull final UsersViewHolder1 Holder, final int position, #NonNull
Ad ad) {
Holder.setTitle(ad.getTitle());
Holder.setPrice(ad.getPrice());
Holder.setCategory(ad.getCategory());
Holder.setImage(ad.getImage(), getContext());
Holder.setTime(ad.getTime());
String user_id = getRef(position).getKey();
final String kk = user_id.toString();
Holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent mew = new Intent(getActivity(), ExpandActivity.class);
mew.putExtra("user_id", kk);
startActivity(mew);
}
});
Holder.mFavouritesBlack.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).child("fav_status").setValue("Added as fav").addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(),"Added to Fav",Toast.LENGTH_SHORT).show();
if (Holder.mFavouritesBlack.isShown())
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}
});
return true;
}
});
Holder.mFavouritesYellow.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).removeValue().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(),"Removed from Fav",Toast.LENGTH_SHORT).show();
if (Holder.mFavouritesYellow.isShown())
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
});
return true;
}
});
}
What you are trying to implement is selection inside a recyclerview which requires saving state, that is you will have to save the favourite items say in a SparseBooleanArray which can be used to save favourite adapter positions, and inside onBindViewHolder check if the favourites array contains the adapter position and toggle imageview (There is no need to use two images instead you can change the color of drawable), please refer this artcle
That is because you are saving the flags when a click happened,but when the views are redrawn you are not resetting the images accordingly. Inside the onBindViewHolder add the following code.
//Replace the if condition statement with the state value check(Abstract code shown below)
if(mFav.child(puid).child(kk).child("fav_status").getValue(),equals("Added as fav")){
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}else{
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
After 2 days of messed up searches and work I finally removed my the problem was that recycler view isn't able to hold the state by itself after change, that's why we need to provide a way to store the state (or the image in my case) so that it can remember it everytime it recycles the view, but instead I added the direct statement through which it checks whether the favourite node is present in database or not and based on that the buttons behaved. Below is the code.
mFav.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.child(puid).hasChild(kk)){
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}else{
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Holder.mFavouritesBlack.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).child("fav_status").setValue("Added as fav").addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(), "Added to Fav", Toast.LENGTH_SHORT).show();
if (!itemStateArray.get(adapterPosition, false))
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}
});
return true;
}
});
Holder.mFavouritesYellow.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).removeValue().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(), "Removed from Fav", Toast.LENGTH_SHORT).show();
if (itemStateArray.get(adapterPosition, false))
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
});
return true;
}
});
But huge thanks to everyone who tried to help.
I have created a bottom sheet using the newly updated support library. Basically, whenever an item in my recyclerview is long-clicked, a bottom sheet is shown (containing a linearlayout which contains a listview). But whenever I tap the items in the listview nothing happens. I added toasts and it is never triggered when I tap on the sheet items. Any ideas? Thanks in advance!
Here is the listview initialization method:
public void initSheet() {
bottomSheet = findViewById(R.id.list_sheet);
ListAdapter adapter = new ListAdapter(this, R.layout.custom_sheet_row, getSheetInfo(), "Sheet");
list = (ListView) findViewById(R.id.list_sheet_list);
list.setAdapter(adapter);
behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setHideable(true);
}
Here is the recyclerview long click:
#Override
public void onLongClick(View view, int position) {
final String itemText = ((TextView) view.findViewById(R.id.textRow)).getText().toString();
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(ListActivity.this, "sdjakfjs", Toast.LENGTH_SHORT).show();
switch (position) {
case 0:
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_TEXT, itemText);
startActivity(Intent.createChooser(sharingIntent, "Share the item"));
break;
case 1:
final ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(ClipData.newPlainText("New", itemText));
break;
case 2:
editText(itemText, position);
break;
case 3:
listAdapter.deleteItem(position);
break;
}
behavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
});
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
try this.
implement custom clicklistener it will work pefectly.
// creating interface to handle clicks for Recycler view items
public interface ClickListener
{
void onClick(View view,int position);
void onLongClick(View view,int position);
}
public static class CustomRecyclerTouchListener implements RecyclerView.OnItemTouchListener
{
private GestureDetector gestureDetector;
private MainActivity.ClickListener clickListener;
public CustomRecyclerTouchListener(Context context,final RecyclerView recyclerView,final MainActivity.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 recyclerView, MotionEvent motionEvent) {
View child=recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
if(child!=null && clickListener!=null && gestureDetector.onTouchEvent(motionEvent))
{
clickListener.onClick(child,recyclerView.getChildPosition(child));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean b) {
}
}
}
Then implement like this.
recyclerView.addOnItemTouchListener(new CustomRecyclerTouchListener(getApplicationContext(), recyclerView, new ClickListener() {
#Override
public void onClick(View view, int position) {
User user=users.get(position);
Toast.makeText(MainActivity.this,user.getName()+" is clicked",Toast.LENGTH_SHORT).show();
}
#Override
public void onLongClick(View view, int position) {
User user=users.get(position);
Toast.makeText(MainActivity.this,user.getName()+" is long clicked",Toast.LENGTH_SHORT).show();
}
}));
For more details refer here:- http://coderzpassion.com/android-working-with-recycler-view/
Ok, what I ended up doing was creating 4 textviews inside of the linear layout instead of using the listview. Then I just added an onclick listener for all of the textviews to do their respective commands
In the code below, onItemLongClick works only when I comment out the onTouchListener. I need to be able to register swipes as well as long clicks. What am I doing wrong?
public class MainPageActivity extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
...
getListView().setLongClickable(true);
getListView().setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(getApplicationContext(), "long click", Toast.LENGTH_SHORT).show();
return true;
}
});
getListView().setOnTouchListener(new OnSwipeTouchListener() {
public void onSwipeBottom() {
Toast.makeText(MainPageActivity.this, "bottom", Toast.LENGTH_SHORT).show();
}
});
}
}
If you are overriding onTouch, onDown, or other methods like that, in OnTouchListener, SimpleGestureListener or the like, you need to make sure that your are returning false, in order for the event to propagate correctly.
I have a onClickListener on a textview and the textview has the flag that it's selectable.
But the onclick event I specified is only called when the textview is clicked a second time.
After the second time it calles the onclick right, but if a other textview that also is selectable with a onclicklistener it also is only called the second time, then it works fine, but then the other one works only the second time again. I can't find the source of these weird events.
telefoonTXT.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {startTelIntent();}}
);
urlTXT.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {startWebIntent();}
});
I faced this issue as well. Whenever text view is touched firstly onTouch, then OnSelection and at last OnClick is called.
If i understand your problem clearly you want to select text in text view when user double taps or long presses like the usual text selection but when user simply clicks it once u want the onClick to function. I think the following might help you.
Add a gestureDetector to your text View.
GestureDetectorCompat mDetector;
mDetector = new GestureDetectorCompat(this, new GestureDetector.SimpleOnGestureListener());
mDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// This is where u add your OnClick event
startTelIntent();
return false;
}
#Override
public boolean onDoubleTap(MotionEvent e) {
Log.d("dtttt", "double tap");
return false;
}
#Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
});
telefoonTXT.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mDetector.onTouchEvent(event);
return false;
}
});
In my case focus change listener works, but be aware for cases when you use it in androidTv that you move with D-pad
textView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus && textView.measuredHeight > textView.lineHeight * textView.lineCount) {
//your click event
}
}
I check if text can be scrolled then don't take the click event
The accepted answer is good. But I had one additional issue with it: When I have some selection text in textview, I want to tap on textview to only deselecting the text - without perfoming on click listener. And perform on click only with no text selection.
So below is my solution:
#SuppressLint("ClickableViewAccessibility")
public static void setOnClickGestureDetectorListener(TextView textView, Context context, View.OnClickListener onClickListener){
if (textView == null || context == null || onClickListener == null)){
return;
}
final GestureDetectorCompat detector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener());
detector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
onClickListener.onClick(textView);
return false;
}
#Override
public boolean onDoubleTap(MotionEvent e) {
return false;
}
#Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
});
textView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if ( v instanceof TextView ) {
TextView textView = (TextView)v;
if (textView.getSelectionStart() >= 0 && textView.getSelectionEnd() > textView.getSelectionStart()){
return false;
}
detector.onTouchEvent(event);
}
return false;
}
});
}
And calling example is below:
setOnClickGestureDetectorListener(textView, getContext(), new View.OnClickListener() {
#Override
public void onClick(View v) {
// This is where u add your OnClick event
}
});
set this ...
TextisSelectable = "false"
i think it will be work correctly