I have scoured the web in search of an answer to a question that has been bugging me for days. I am making a widget that allows a user to pan the entire widget by dragging (around the Y axis only) within the viewing area. I then have a smaller view (like a button, listens to onTouchEvent) inside here that the user can also drag. The idea is that the user will drag this view up or down and if they want to go higher or lower they can pan the entire widget and then continue dragging the view higher or lower. Now, I'm having two issues with this. First off, after dragging the main view (whole widget) the view that I would like to then move still resides in the area it once was before translating the entire canvas.
So for example, if I move the entire canvas by 50 in the Y position, I then want to move the smaller view but have to touch in the old position rather than the offsetted one (by 50). So it looks like I don't click the smaller view where it is now, but where it used to be (I hope this makes sense).
Next issue, after I move the smaller view. I am not able to trigger anymore touch events. I'm assuming that's because it was moved outside of its parent (which is still viewable since I set clipChildren to false) and its "z-order" is lower than the other views in the layout. Is there a way to always position this on top? I am using Android API 17. Even if I set this smaller view (that I am moving when touched and ACTION_MOVE event is triggered) as the last child in the main layout, I need to be able to drag it out of here (which I can) and continue to drag it on a new onTouchEvent. ANY help is greatly appreciated. I added some layout xml and code snippets below to help.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<RelativeLayout
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
android:id="@+id/ref_image"
android:layout_width="wrap_content"
android:layout_height="216dp"
android:src="@drawable/my_ref_image"
android:layout_centerInParent="true"
android:clipChildren="false"/>
<RelativeLayout
android:id="@+id/selection_view"
style="@style/MyStyle"
android:layout_alignTop="@id/ref_image"
android:layout_marginTop="116dp"
android:clipChildren="false"
android:clipToPadding="false">
<RelativeLayout
android:id="@+id/selection_area"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
android:id="@+id/underlay_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/translucent_image"
android:layout_centerInParent="true"/>
<ImageView
android:id="@+id/point_area"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/point_image"
android:layout_centerInParent="true"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
So the snippets of code that is of interest:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (DEBUG) {
Log.d(TAG, TAG + "::onDraw: ");
}
canvas.translate(0, backgroundPositionY);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
Log.d(TAG, TAG + "::onTouchEvent: parent touch event");
switch (action) {
case MotionEvent.ACTION_DOWN: {
final float y = ev.getY();
// Remember where we started
lastTouchY = y;
if (DEBUG) {
Log.d(TAG, TAG + "::onTouchEvent: parent ACTION_DOWN");
}
return true;
}
case MotionEvent.ACTION_MOVE: {
final float y = ev.getY();
// Calculate the distance moved
final float dy = y - lastTouchY;
backgroundPositionY += dy
// Remember this touch position for the next move event
lastTouchY = y;
// Invalidate to request a redraw
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
lastTouchY = ev.getY();
}
}
return false;
}
// called upon initialization (selectionArea refs view id = selection_area)
private void initPointListener() {
this.setClipChildren(false);
this.setClipToPadding(false);
if (selectionArea != null) {
selectionArea .setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
RelativeLayout.LayoutParams pointParams = (RelativeLayout.LayoutParams) selectionArea.getLayoutParams();
final int action = motionEvent.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: {
pointLastTouchY = motionEvent.getY();
}
break;
}
case MotionEvent.ACTION_MOVE: {
float moveY = motionEvent.getY();
final float dy = moveY - pointLastTouchY;
pointPosY += dy;
selectionArea.setY(pointPosY);
break;
}
}
return true;
}
});
}
}
Note that I have tried setting the padding and I have referenced the following on SO with no good results:
How to translate the canvas and still get the touch events on the correct places
Android : click / touch event not working after canvas translate