Let's say:
Activity1 contains some items which will be dragged
Activity2 contains some "boxes" which will be filled with Activity1's item. The boxes already have drag listener.
I want to drag item from Activity1 into Activity2
I tried these method:
I implement onLongClickListener() on Activity1 items and use startDrag() there. Then I open Activity2. I could make the drag shadow appear but the boxes cannot receive the item. In fact, they doesn't respond to any DragEvent.
I implement onLongClickListener() on Activity1 items, but only to pass the data into Activity2. Then I use startDrag() when Activity2 start(specifically in onResume()). Here, the shadow not appear and the boxes doesn't respond to any DragEvent.
Is there any way to make this possible?
its possible using two fragment of view pager instead of 2 activity and you can set logic of drag and drop in onTouch() or dispatchTouch().
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
using dispatchTouch() in activity of fragment or
viewPager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
using touch event of view pager you can set drag and drop logic within inside.
I hope this idea can help you.
Related
I have a recyclerview with items inside, I would like to distinguish between swipe (I am moving the element horizontaly making some action and setting it back to its original place) singleTouch and longClick, what is the best Practice of achieving it?
I seen a lot of implementations here, but none that work\super messy(and also dont work properly), if i implement custom gestureDetector and switchcase inside it works but it takes the phone about a second to react, if i implement onTouch in only catches onTouch, if I dont the onClick and onLong work but not the swipe
currently only the swipe works:
item.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
logd("TAG","2");
return false;
}
});
}
item.setOnClickListener(v -> {
logd("TAG","1");
});
item.setOnLongClickListener(v -> {
logd("TAG","2");
});
any advice would be appreciated,
Thanks
I have an Activity with a ViewPager with 3 dynamically created Fragments. Each page has numerous Buttons and ImageButtons that activate on their own onTouch..MotionEvent.ACTION_DOWN.
The problem I'm having is that these buttons activate accidentally when am trying to swipe the ViewPager.
Can anyone recommend a way to keep this from happening?
Thanks
Josh
Instead of using onTouch..MotionEvent.ACTION_DOWN.
on the ImageButton I will make them implement;
.OnItemClickListener() /This ensures that only when clicked they will call the desired functionality, I suggest you to check it out this way and let me know.
Hope it helps, more info at; The Documentation for OnItemClickListener
I think that the flow you are following is not really good, the button also has the business code to handle the ACTION_DOWN touch event and the parent (ViewPager) always need handle touch event to detect the scroll events, so button will handle the ACTION_DOWN touch event first and then pass the touch to ViewPager.
You can move the business code into the OnClickListener of Button or another way you should let the button intercept the touch event and don't pass it to ViewPager (Parent View).
This can be easy to handle by customize the Viewpager class and add a variable in the custom ViewPager like this :
private boolean mTouchEnable = true;
#Override
public boolean onTouchEvent(MotionEvent arg0) {
if (!mTouchEnable) {
return false;
}
return super.onTouchEvent(arg0);
}
The button will need a reference to the viewPager and set the mTouchEnable = false in ACTION_DOWN and true in ACTION_UP
I did a viewpager of buttons and I was able to replicate the issue.
I solved to this way:
My buttons have a listener OnClickListener
optionButton.setOnClickListener(this);
public void onClick(View v) {
// your code here
}
Then I add this button to my customPagerAdapter
In your customViewPager you have to override the onInterceptTouchEvent method like this:
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
super.onInterceptTouchEvent(ev);
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
return true;
}
else{
return false;
}
}
This code will intercept the MotionEvent.ACTION_MOVE in child views (return true) and won't intercept MotionEvent.ACTION_DOWN neither onClick event in the child views.
I'm wondering why click events doesn't bubble up if I click inside a RecyclerView.
My scenario uses a simple RecyclerView to show some TextViews, while its parent View has an OnClickListener registered to perform some action if someone clicks into the view.
If I click on e.g. a TextView the click event bubbles properly up to the parent. But if I click onto the RecyclerView the click doesn't bubble up.
The weird thing is, that if I set an OnClickListener directly on the RecyclerView it is also never fired. I assume that is the root of all evil.
So, why does my RecyclerView don't receive any click events? Why doesn't its parent receive any click events?
Hierarchy looks like this:
- View (has an OnClickListener) <- Why no clicks?
- RecyclerView (clickable=false)
- TextView
- TextView
....
I experimented with setFocusable() and setClickable(), but without luck.
PS: My current solution sets an OnClickListener on each TextView inside the RecyclerView and uses getParent() to propagate the click to the parent view using performClick() manually.
I use the special class handler for RecyclerView, the RecyclerView.OnItemTouchListener. I can be added from the consuming class. Here is the default implementation of the handler class:
recyclerView.addOnItemTouchListener( new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
//Put your code here.
//Called 2 times per touch, on pressdown and on release.
return false; //true will disable scroll view.
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
setDefaultBottomBar();
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
Idea: I want to display an image as background. On this image, somewhere on the screen there is a little clickable View. On top of this all, a black draggabke image with a little transparent whole (displaying the underlying Views).
This is solved with a FrameLayout, whereas the image is the first frame, the View is the second frame and the ''Viewport'' is the third frame.
Now the goal is, that the user can click that second frame, if it is visible in the viewport. The problem is, that this transparency is only ''in the png'', not in the frame itself. So the solution would be to propagate the OnClick coordinates to the underlying frame. How is this possible? Is there a functionality for a FrameLayout in such cases?
Making the upper layer as clickable false, i think the click event should be ignored by it and passed to the second frame
Create a custom class that extends FrameLayout
Add the following overridden methods
#Override public boolean onTouchEvent(MotionEvent event) {
return false;
}
#Override public boolean onInterceptTouchEvent(MotionEvent event) {
return true;
}
Then add touch listener to frame layout like
framelayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
underLyingView.onTouchEvent(motionEvent);
return false;
}
});
This will pass onclick event to the view underLyingView which lies under FrameLayout
(Please note that the behavior described in this question only appeared because of something else seemingly unrelated we were doing. See the accepted answer.)
We have an Android activity with a GridView and a SlidingDrawer inside of a RelativeLayout. The way this activity responds to the trackball (or cursor keys) is rather odd. The focus will move among the items in the GridView, but whenever the cursor moves in a direction "out" of the GridView. (e.g. up when at the top, left when already at the leftmost item) the sliding drawer opens or shut. Notably, the focus stays on the same item in the GridView---it does not move to the sliding drawer.
With a trackball this is particularly horrible, as spinning the trackball past your real destination will cause the sliding drawer to repeatedly open and close.
We've determined that we can turn off the trackball entirely by overriding onTrackballEvent(). We'd prefer to have the trackball and cursor work normally on the GridView but not cause the sliding drawer to open or close. In principle we'd also like the trackball to focus on the various contents of the sliding drawer when it is open.
How?
You may consider creating custom views extending GridView and SlidingDrawer and using custom implementations of onInterceptTouchEvent and onTouchEvent for the GridView and a custom implementation just for onInterceptTouchEvent for the SlidingDrawer. You may not need to implement a custom SlidingDrawer depending on what user interactions may be triggered on the handle
for your custom GridView, give it an interface maybe defined like this:
public interface MyGridViewListener {
public boolean shouldPreventScroll();
}
return if your custom SlidingDrawer is opened. this returned value will be used to determine if actions should be performed(for onInterceptTouchEvent and onTouchEvent methods) on the GridView. So when the SlidingDrawer is opened, actions performed on the GridView will not trigger anything on the SlidingDrawer.
Activity:
MyGridView gridView = (MyGridView) findViewById(R.id.gridView);
gridView.setMyGridViewListener(new MyGridViewListener() {
#Override
public boolean shouldPreventScroll() {
return slidingDrawer.isOpened();
}
});
MyCustomGridView:
shouldIntercept will be called whenever some touch/track event happens on the GridView.
private boolean shouldIntercept() {
boolean shouldIntercept = false;
if(myGridViewListener != null) {
shouldIntercept = myGridViewListener.shouldPreventScroll();
}
return shouldIntercept;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return shouldIntercept() ? true : super.onInterceptTouchEvent(ev);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return shouldIntercept() ? true : super.onTouchEvent(ev);
}
#Override
public boolean onTrackballEvent(MotionEvent event) {
return shouldIntercept() ? true : super.onTrackballEvent(event);
}
public MyGridViewListener getMyGridViewListener() {
return myGridViewListener;
}
public void setMyGridViewListener(
MyGridViewListener myGridViewListener) {
this.myGridViewListener = myGridViewListener;
}
I hope this points you in a right direction or at least helps
While playing around with a custom sliding drawer I set the layout of the handle to some odd value, something like
handle.layout(0, 0,0, 0);
to make the handle disappear but dragging a finger from the side of the screen would still open the sliding drawer, which is what I didn't want, so I set
handle.layout(10000, 10000, 10000, 10000);
which moved it way outside the viewable area and the drawer could no longer be pulled out manually by dragging from the side of the screen. After looking at the source code its teh position of the handle that determines the sliding of the drawer, get rid of the handle and it should solve your problem.
If you need to open/close the drawer call animateOpen()/animateClose()
As it turned out, we caused this problem by an unrelated bit of foolishness. We wanted the MENU key to open and close the SlidingDrawer. We did this by overriding onPrepareOptionsMenu():
public boolean onPrepareOptionsMenu (Menu menu) {
slidingDrawer.animateToggle();
return true;
}
This works fine; but it turns out it can be called when the menu is not about to be opened. In particular, if the Activity uses setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT), then an unhandled key event will end up accessing the menu. This includes trackball motion off the edge of the screen.
The less dumb way to get the desired behavior is
public boolean onKeyUp(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_MENU) {
slidingDrawer.animateToggle();
}
return super.onKeyUp(keyCode,event);
}
Meanwhile, we can get the trackball to move within the SlidingDrawer when it is open by setting up a SlidingDrawer.OnDrawerOpenListener which calls
slidingDrawer.getContent().requestFocus();
Finally it seems like a good idea to call
slidingDrawer.getHandle().setFocusable(false);