I am using touch listener on my views to drag them. findViewById(R.id.myimage1).setOnTouchListener(new MyTouchListener());
Unfortunately there are lots of views therefore I have to stack them in a scrollview.
Here is the touch listener:
private final class MyTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}
}
Because of this touch listnener I am unable to scroll the listview.
When I try to scroll, the touch listener fires and view's shadow is created instead of scroll.
How can I use both events or can use Drag n Drop functionality in a ScrollView
Related
I created a recycler view where the items can be dragged. The following is from my adapter:
public void onBindViewHolder(final FootballPitchMainAdapter.ViewHolder holder, int position) {
holder.rvPlayerNameTop.setText("testing");
holder.linearLayoutFull.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
view);
view.startDrag(data, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}
});
Now this does work, I can drag the linearLayout, which contains an imageView and a texview. The drag allows me to move the items out of the recyclerview.
If I used motion, I couldn't move the linearlayout frame out of the RV.
But my problem is, once I drag the view, I want to be able to place it anywhere on the screen.
So in the class where the RV is created, I set the following:
pitchRelativeLayout.setOnDragListener(new MyDragListener());
class MyDragListener implements View.OnDragListener{
#Override
public boolean onDrag(View v, DragEvent event) {
switch(event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
//Do nothing
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED :
break;
case DragEvent.ACTION_DRAG_LOCATION :
break;
case DragEvent.ACTION_DRAG_ENDED :
// Do nothing
break;
case DragEvent.ACTION_DROP:
View view = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) view.getParent();
owner.removeView(view);
RelativeLayout container = (RelativeLayout) v;
container.addView(view);
view.setVisibility(View.VISIBLE);
break;
default: break;
}
return true;
}
}
PitchLayout is a relativelayout which covers the entire screen. The idea is just to drag an item from RV and drop it anywhere.
Here is an image which I hope explains this better:
I am trying to tell the relative layout to listen to the drag item and on the drop, place it here.
The above code is from online tutorials I have tried, answers from Stackover Flow
I have an EditText (vertically scrollable) inside one of the fragments in a ViewPager (horizontally swipable).
By default, touch events inside the EditText can swipe the ViewPager but not scroll the EditText. By using the code below (which I don't really understand), touch events inside the EditText can scroll the EditText but not swipe the ViewPager:
editText.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
v.getParent().requestDisallowInterceptTouchEvent(! ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP));
return false;
}
});
How can I simultaneously allow swiping of the ViewPager and scrolling of the EditText?
You can handle this according to the solution given here.
pager.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View p_v, MotionEvent p_event)
{
editText.getParent().requestDisallowInterceptTouchEvent(false);
// We will have to follow above for all scrollable contents
return false;
}
});
For the EditText, you will have to add this snippet.
editText.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View p_v, MotionEvent p_event)
{
// this will disallow the touch request for parent scroll on touch of child view
p_v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
Hope it helps...
I am trying to make a grid of image views, that when i drag another view over them(this view essentially acts as a mouse pointer), it changes the image I drag over in the grid to a different image. When I drag the "mouse" view away it will go back to normal.
Right now I have my mouse cursor view moving and have a grid of image views implemented with a grid view using a custom adaptor ( pictured below)
I can drag my cursor around but when ever I try to drag inside the gridview, it calls the image on the gridview's ontouch listener(only when i click on the image view, not when I slide over it). I also cannot seem to get onHover working on the images in the image View.
Also, if the mouse view is covering one of the grid images, the ontouchlistener of the image view the grid is not called.
What is the best way( types of views, etc) to use to go about implementing this?
Here is some relevant code from what I have so far.
This is where I set up my grid view in my activity
GridView gridView;
gridView = (GridView) findViewById(R.id.gridView);
gridView.setAdapter(new ImageAdapter(this,new String [25]));
gridView.setOnDragListener(new MyDragListener());
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
}
});
gridView.setClickable(false);
This is the getView function in my adapter
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = inflater.inflate(R.layout.vibe_pad_section, null);
final ImageView imageView = (ImageView) gridView
.findViewById(R.id.grid_item_image);
imageView.setImageResource(R.drawable.vibepadcircle);
imageView.setPadding(10,10,10,10);
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent e) {
Log.e("here","here");
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
Log.e("here2","here2");
}
imageView.setImageResource(R.drawable.bar_high);
return true;
}
});
VibePad.padTargets.add(imageView);
} else {
gridView = (View) convertView;
}
return gridView;
}
class MyDragListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
final int action = event.getAction();
ClipData dragData;
View p = (View) v.getParent();
Object index = p.getTag();
final int which = Integer.parseInt(index.toString());
boolean handled = true;
Log.e(" in on drag","in on drag") ;
switch (action) {
case DragEvent.ACTION_DRAG_EXITED:
// Report the drop/no-drop result to the user
((ImageView) v).setImageResource(R.drawable.bar_high);
break;
case DragEvent.ACTION_DRAG_ENTERED:
// just drop it
((ImageView) v).setImageResource(R.drawable.vibepadcircle);
break;
default :
break;
}
return handled;
}
You need to create a class that extends OnDragListener:
When ACTION_DRAG_ENTERED occurs, you can change the underlying image to something else. When you exist (you've dragged the view outside the bounding box of the the image on your gridview) then you can change it back to it's original image
class MyDragListener implements OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
final int action = event.getAction();
ClipData dragData;
View p = (View) v.getParent();
Object index = p.getTag();
final int which = Integer.parseInt(index.toString());
boolean handled = true;
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
dragSku = event.getClipDescription().getLabel().toString();
break;
case DragEvent.ACTION_DRAG_ENDED:
// Report the drop/no-drop result to the user
final boolean dropped = event.getResult();
compareInMotion = false;
BaseAdapter lva = (BaseAdapter) gridview.getAdapter();
lva.notifyDataSetChanged();
break;
case DragEvent.ACTION_DROP:
// just drop it
((ImageView) v).setImageBitmap(emptyImg);
setUpCompareItem((ImageView) v, dragSku); break;
default :
break;
}
return handled;
I implemented a gesture detector to find out when the user will fling my listview (and when the last element of the list is in view) so that I may add more data to the list. The list has a custom adapter that I've built. Each row has a few textviews in it and an image button. I was using the imagebutton (which is an arrow) with a click listener in my adapter to open another activity related to the pressed row.
Management wants the user to be able to click anywhere on the row in order to activate it. So:
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
View v = convertView;
final ViewHolder viewHolder;
.....
//viewHolder.ibShipmentDetails.setOnClickListener(new OnClickListener()
v.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View view)
{
....
}
}
But now, my fling detector won't work correctly. Sometimes it responds and afterwards works correctly; restart the activity, again it doesn't work.
Here is my gesture detector:
class MyGestureDetector extends GestureDetector.SimpleOnGestureListener
{
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if((e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY))
{
if(!loading && ((totalItemCount - visibleItemCount) <= firstVisibleItem))
{
if(allTabSelected)
{
allPageNo++;
}
else
{
openPageNo++;
}
new GetShipmentPreviews().execute(1);
}
}
}
And in my activity:
gestureDetector = new GestureDetector(this, new MyGestureDetector());
gestureListener = new View.OnTouchListener()
{
public boolean onTouch(View v, MotionEvent event)
{
return gestureDetector.onTouchEvent(event);
}
};
listView.setOnTouchListener(gestureListener);
What should I do to keep v.setOnClickListener and the onFling() command intact?
Turns out my MotionEvents from onFling are null. This apparently happens because the event gets somehow "eaten" by the onClickListener from my custom adapter.
I got the solution from this answer : https://stackoverflow.com/a/7159738/1688731
I added the following code to my Activity class:
#Override
public boolean dispatchTouchEvent(MotionEvent ev)
{
super.dispatchTouchEvent(ev);
return gestureScanner.onTouchEvent(ev);
}
You should use listViev.setOnItemClickListener() once, instead of calling v.setOnClickListener() for all list items.
In my app, I'm making a search interface in which the SearchView collapses and expands when it loses and gains focus respectively. However, the losing focus thing is only happening in two cases:
When the back button is pressed.
When the home icon beside the SearchView is pressed.
I want it to lose focus (and hence collapse) if the user clicks not only on these two things, but anywhere else on the screen (e.g., any button or any blank portion of the screen without a view on it).
Well I found out the following solution. I used setOnTouchListener on every view that is not an instance of searchview to collapse the searchview. It worked perfect for me. Following is the code.
public void setupUI(View view) {
if(!(view instanceof SearchView)) {
view.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
searchMenuItem.collapseActionView();
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
This is the answer I referred to.
Well, I have another simpler and tidier way of doing this. If you're using search widget as an action view in the toolbar (https://developer.android.com/guide/topics/search/search-dialog#UsingSearchWidget), you might want to make the SearchView lose focus and hide the keyboard when user touches anywhere else on the screen.
Instead of iterating and setting up touch listeners on every view in the hierarchy except the SearhView, you can simply make use of this solution since the SearchView has a AutoCompleteTextView in it.
Step 1: Make the parent view(content view of your activity) clickable and focusable by adding the following attribute
android:clickable="true"
android:focusableInTouchMode="true"
Step 2: Set OnFocusChangeListener on the SearchView AutoCompleteTextView
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem search = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) search.getActionView();
// get a reference of the AutoCompleteTextView from the searchView
AutoCompleteTextView searchSrcText = searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
searchSrcText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
});
return super.onCreateOptionsMenu(menu);
}
That's it! Hopefully this is useful for future readers :)
in my case, i had to stop the search and close the keyboard, whenever user clicks on any other view, this worked for me.
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View view = getCurrentFocus();
if (view != null && view instanceof EditText) {
Rect r = new Rect();
view.getGlobalVisibleRect(r);
int rawX = (int) ev.getRawX();
int rawY = (int) ev.getRawY();
if (!r.contains(rawX, rawY)) {
hideSoftKeyboard(MainActivity.this);
}
}
}
return super.dispatchTouchEvent(ev);
}
This works for me, mOptionsMenu is saved in onCreateOptionsMenu:
public void setupUI(View view) {
//Set up touch listener for non-text box views to hide keyboard.
if(!(view instanceof EditText)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(MainActivity.this);
if(mOptionsMenu == null) return false;
MenuItem searchMenuItem = mOptionsMenu.findItem(R.id.action_search);
if(searchMenuItem == null) return false;
((SearchView)searchMenuItem.getActionView()).clearFocus();
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
try this. It will make the searchView collapse when click anywhere on the screen.
searchView.isIconified = true