I have a simple Button, that has a touch listener. Once it's triggered on ACTION_DOWN action, a ListView appears on top of that button (so that the ListView is under user's finger).
What I want is to "pass" that touch event from Button to that ListView, so that when moved up/down, the list view would also scroll up/down.
Simply put:
User touches a Button
A list view appears on covering that button
WITHOUT RELEASING A FINGER, user starts moving finger to the top/bottom screen edge,
The list view scrolls.
UPDATE
I tried making a custom ListView component with onInterceptTouchEvent overridden, but I do not clearly get what should go into that method?
You should create a custom class extending ListView, then override the method onInterceptTouchEvent(MotionEvent e). That method gets called whenever a view inside the list is touched.
You don't need any custom component.
Set your button onTouchListener as:
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
switch (motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
// popup the listView
break;
case MotionEvent.ACTION_MOVE:
// lstPopup is your ListView
lstPopup.dispatchTouchEvent(motionEvent);
break;
case MotionEvent.ACTION_UP:
// do other stuff
}
return false;
}
});
And set your listView onTouchListener as:
lstPopup.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE)
{
lstPopup.setSelectionFromTop(0, (int) motionEvent.getY());
}
return false;
}
});
Related
I am working on an Audio Recording App. It works in a way that when the user presses and moves the record button, the button moves along with the finger. I have created a boundary and when the finger crosses that boundary I want the button to perform the hide() animation and get back to it orginal position.
The whole process works fine if the MotionEvent.ACTION_UP or MotionEvent.ACTION_CANCEL event is occurred, but the hide() operation is not occurring even if the touch crosses the boundary. The button plays a back and forth motion sometimes when it is outside the boundary. The touch event is still being called even if I set the visibility of the view to false.
I get the output in the logcat as well (Log.e("MSG","boundary crossed");).
This is the code:
int recordButtonStartX;
microPhoneListner=new View.OnTouchListener() {
#Override
public boolean onTouch(View v, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
recordButtonStartX = (int) event.getX();
this.floatingRecordButton.display(event.getX());
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
this.floatingRecordButton.hide(event.getX());
break;
case MotionEvent.ACTION_MOVE:
int tempX = (int) event.getX();
if ((recordButtonStartX - tempX) > 200) {
Log.e("MSG","boundary crossed");
this.floatingRecordButton.hide(event.getX());
}
else
{
this.floatingRecordButton.moveTo(event.getX());
}
break;
}
recordMsgButton.setOnTouchListener(microPhoneListner);
To release the onTouchListener for any View set the listener to null.
recordMsgButton.setOnTouchListener(null);
or
After your condition satisfied you can set other listener to that View.
Make another listener
public final OnTouchListener mTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent rawEvent) {
return false;
}
};
When you want to disable the listener then set other listener to that view
v.setOnTouchListener(mTouchListener);
I have a listview with a padding top. I need to detect when the empty space on top is clicked.
I tried OnClickLister but I cannot use it on ListView. OnItemClickListener works only when I click on a row.
you can add header with nothing in it to listView and set onClickListener for that header
Use a Space with a listener attached on it instead of padding. Or add a listener to the parent view and look for that event.
You can use OnTouchListener and check if the Y coordinate of the MotionEvent is less than your padding :
listView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_UP :
final int padding = getResources().getDimensionPixelSize(R.dimen.listView_padding);
if (motionEvent.getY() < padding) {
// do stuff here
return true;
}
break;
}
return false;
}
});
I have two view pager, one is nested in the other. To get the correct behaviour (swiping the inner view pager without changing the outer) I had to override the inner view pagers onTouchListener and put all my onTouch/onClick logic into it (got the idea from here).
Works all fine, but since I don't have a onClickListener anymore I lost my selector effect. When I put android:clickable="true" on the layout element I get my selector effect, but the view pagers behaviour is wrong again.
Is there any way to achieve the selector effect out of the onTouchListener?
innerPager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
Log.d(DEBUG_LOG, "Single tap.");
return true;
} else if(event.getAction() == MotionEvent.ACTION_DOWN && v instanceof ViewGroup) {
((ViewGroup) v).requestDisallowInterceptTouchEvent(true);
}
return false;
}
});
This solved it for me. Just added the following code to my OnTouchListener and replaced the card view with my inner view pagers current item:
// Since the host view actually supports clicks, you can return false
// from your touch listener and continue to receive events.
myTextView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent e) {
// Convert to card view coordinates. Assumes the host view is
// a direct child and the card view is not scrollable.
float x = e.getX() + v.getLeft();
float y = e.getY() + v.getTop();
// Simulate motion on the card view.
myCardView.drawableHotspotChanged(x, y);
// Simulate pressed state on the card view.
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
myCardView.setPressed(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
myCardView.setPressed(false);
break;
}
// Pass all events through to the host view.
return false;
}
});
I am developing an android application which has a scrollview. I have overriden my view from ScrollView and have implemented the onScrollChanged method. As the scrollview scrolls and reaches the bottom, it loads more products and add them to scrollvew. I am having a strange issue. First time when products loads and I try to drag up the scrollview, onScrollChanged never happens. Then I googled and found something:
scrollView.setOnTouchListener(new ListView.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(true);
break;
}
// Handle ListView touch events.
v.onTouchEvent(event);
return true;
}
});
After adding this, when I try to drag the scrollview from empty area of scrollview, it starts to call onScrollChanged and afterwards I start dragging from anywhere else, onScrollChanged is being called. My question is, why it is behaving like that? It should call onScrollChanged from whatever the touch event starts. I hope, I explained my point well. Any solution?
Why don't you use endless adapter with a view like ListView or GridView to achieve the desired behavior instead
I have several buttons and I would like to press on one of them and drag through another presing them. Could you tell me which MotionEvent or another functionality should I use. I'm using onTouchListener.
There is an image where you can see what I want to do (first ACTION_DOWN on 1st button and drag through 2nd-7th buttons still pressing the screen) and finally press every white buttons:
Below is my onTouch button code:
button1 = (Button) findViewById(R.id.button1);
button1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
soundIDs[0] = sound.play(R.raw.sample1);
button1.setBackgroundResource(R.drawable.white_clicked);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
sound.stop(soundIDs[0]);
button1.setBackgroundResource(R.drawable.white);
break;
}
return false;
}
});
You are setting the OnTouchListener on just the one button. That's not going to help you know when the pointer moves (e.g. user drags his finger) into another button.
You could set an OnTouchListener on the view that contains the buttons. Then check for ACTION_DOWN, ACTION_MOVE, and ACTION_UP events. You would then have to do some simple hit detection to figure out which button to activate.
Something along the lines of:
getWindow().getDecorView()
.findViewById(android.R.id.content)
.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
int action = event.getAction();
if (action != MotionEvent.ACTION_DOWN
&& action != MotionEvent.ACTION_MOVE
&& action != MotionEvent.ACTION_UP) return false;
Rect hitRect = new Rect();
Button button;
for(int i = 0; i < myButtons.size(); i++) {
button = myButtons.get(i);
button.getHitRect(hitRect);
if (hitRect.contains((int)event.getX(), (int)event.getY())) {
button.setText("hit!");
}
}
return true;
}
});
Where myButtons is an ArrayList of your buttons (piano keys in your example).
Also, you'd probably want to modify this to properly deactivate the currently active button if the user's touch leaves the button, but doesn't hit another button.
I tested the above code on an android device with a layout that has 3 buttons in a row. Dragging your finger across all the buttons causes each button's text to change to "hit!"
Like I said above, you were setting the touch listener on the just one button, that will not work. In this example I have set the touch listener on the entire view for the activity.