Использование одного и того же onTouchEvent в различных действиях
Я использую onTouchEvent
для моего MainActivity.class
. Он отлично работает: если пользователь делает двойной L пальцами, я вызываю фрагмент.
Я хотел бы использовать этот onTouchEvent
в другом Activity
, но я думаю, что он грязный, если я копирую весь свой код.
Теперь для этого я создал для него инструмент TouchListenerImpl
:
class TouchListenerImpl implements View.OnTouchListener {
private boolean movingDownL, movingDownR, movingLeft, movingRight, movingSuccessL, movingSuccessR = false;
private Point oldCoordsL, oldCoordsR, startPointL, startPointR = new Point(0, 0);
private boolean admin_touch = false;
private OnLTouch callback;
void setCallback(OnLTouch c) {
callback = c;
}
interface OnLTouch {
void lTouchSuccess();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("debugTouch", "onTouch");
int pIndexL = event.findPointerIndex(event.getPointerId(0));
int pIndexR = 0;
if(event.getPointerCount() > 1) pIndexR = event.findPointerIndex(event.getPointerId(1));
if(event.getPointerCount() > 1 && event.getX(pIndexL) > event.getX(pIndexR)) {
int tmp = pIndexR;
pIndexR = pIndexL;
pIndexL = tmp;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
movingDownL = true;
movingDownR = true;
movingSuccessL = false;
movingSuccessR = false;
if(event.getPointerCount() > 1) {
startPointR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
oldCoordsR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
}
startPointL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
oldCoordsL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
break;
case MotionEvent.ACTION_MOVE:
int downMinDistance = 300;
int lnrInaccuracy = 10;
int downInaccuracy = 30;
if(event.getPointerCount() > 1) {
if(!movingDownR) {
if(Math.abs(oldCoordsR.x - event.getX(pIndexR)) < downInaccuracy &&
oldCoordsR.y < event.getY(pIndexR)) break;
if(Math.abs(oldCoordsR.y - event.getY(pIndexR)) < lnrInaccuracy &&
oldCoordsR.x > event.getX(pIndexR) && !movingRight) {
movingRight = true;
startPointR = new Point(new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR)));
}
} else {
if (Math.abs(oldCoordsR.x - event.getX(pIndexR)) > downInaccuracy ||
oldCoordsR.y < event.getY(pIndexR)) {
movingDownR = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= downMinDistance){
movingDownR = false;
}
}
}
if(!movingDownL) {
if(Math.abs(oldCoordsL.x - event.getX(pIndexL)) < downInaccuracy &&
oldCoordsL.y < event.getY(pIndexL)) break;
if(Math.abs(oldCoordsL.y - event.getY(pIndexL)) < lnrInaccuracy &&
oldCoordsL.x < event.getX(pIndexL) && !movingLeft) {
movingLeft = true;
startPointL = new Point(new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL)));
}
}else {
if (Math.abs(oldCoordsL.x - event.getX(pIndexL)) > downInaccuracy ||
oldCoordsL.y > event.getY(pIndexL)) {
movingDownL = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= downMinDistance){
movingDownL = false;
}
}
int lnrMinDistance = 50;
if(movingLeft) {
if (Math.abs(oldCoordsL.y - event.getY(pIndexL)) > lnrInaccuracy ||
oldCoordsL.x > event.getX(pIndexL)) {
movingLeft = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= lnrMinDistance) {
movingLeft = false;
movingSuccessL = true;
}
}
if(movingRight) {
if (Math.abs(oldCoordsR.y - event.getY(pIndexR)) > lnrInaccuracy ||
oldCoordsR.x < event.getX(pIndexR)) {
movingRight = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= lnrMinDistance) {
movingRight = false;
movingSuccessR = true;
}
}
if(movingSuccessL && movingSuccessR) {
if (!admin_touch)
{
admin_touch = true;
if (callback != null)
callback.lTouchSuccess();
}
}
oldCoordsL = new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL));
oldCoordsR = new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR));
break;
case MotionEvent.ACTION_UP:
movingDownL = false;
movingDownR = false;
movingLeft = false;
movingRight = false;
break;
default:
return false;
}
return true;
}
private double findDistance(Point p1, Point p2) {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
}
В моей деятельности я вызываю реализацию следующим образом:
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
TouchListenerImpl imp = new TouchListenerImpl();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imp.setCallback(new TouchListenerImpl.OnLTouch() {
@Override
public void lTouchSuccess() {
Log.d("debugTouch", "WORKING !");
}
});
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("debugTouch", "onTouch");
return imp.onTouch(v, event);
}
}
Проблема в том, что я никогда не вхожу в мои журналы. Это не работает вообще...
Ответы
Ответ 1
Вы можете использовать решение @DrilonBlakqori с небольшими изменениями.
Создайте отдельный класс, содержащий общий код, но используйте обратный вызов, чтобы сделать View
видимым.
class TouchListenerImpl implements OnTouchListener {
private OnLTouch callback;
@Override
public boolean onTouch(View v, MotionEvent event) {
// all your code
...
if (callback != null)
callback.lTouchSuccess();
...
}
void setCallback(OnLTouch c) {
callback = c;
}
interface OnLTouch {
void lTouchSuccess();
}
}
В MainActivity
создайте новый экземпляр TouchListenerImpl
и setCallback
, например
TouchListenerImpl imp = new TouchListenerImpl();
imp.setCallback(new OnLTouch() {
public void lTouchSuccess() {
frameLayoutAdmin.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction()
.replace(R.id.framelayout_admin,new AdminLoginFragment())
.commit();
img_close.setVisibility(View.VISIBLE);
}
});
И в MainActivity
, View
, на котором вы хотите обнаружить двойной L на этом View
, установите этот прослушиватель на View
.
view.setOnTouchListener(imp);
Я предполагаю, что вы хотите обнаружить двойной L на основном макете. Для этого вы можете сделать
findViewById(R.id.mylayout).setOnTouchListener(imp);
Надеюсь, это решит вашу проблему.
Ответ 2
Вы можете создать суперкласс Activity, переопределить onTouchEvent и перейти от него.
Что-то вроде этого:
public abstract class BaseActivity extends AppCompatActivity {
@Override
public boolean onTouchEvent(MotionEvent event) {
// Your implementation.
}
}
И затем ваша MainActivity:
public class MainActivity extends BaseActivity {
}
Ответ 3
Вы можете создать суперкласс, который расширяет активность и реализует ваш метод onTouchEvent, и в любом действии, которое вы хотите использовать методом onTouchEvent, расширяет ваш суперкласс. MainActivity также должен был расширить его. Или просто расширьте MainActivity в других действиях, где вы хотите использовать свой метод onTouchEvent.
Ответ 4
Скопируйте весь код вместе с переменными поля в класс, который реализует OnTouchListener
. Затем просто передавайте новый TouchListenerImpl
, когда вам это нужно.
class TouchListenerImpl implements OnTouchListener {
// your field variables
@Override
public boolean onTouch(View v, MotionEvent event) {
// all your code
return false;
}
// getters for the variables that you need
}
Ответ 5
Вам нужно установить слушателя в корне активности, и вам нужно обратить внимание на свою иерархию представлений. События Touch могут быть использованы другими представлениями в иерархии, что может быть причиной того, что вы не получаете никаких журналов.
Я проверил вашего слушателя с минимальными изменениями, и я получил журналы. Однажды я получил двойное касание.
public class TouchListenerImpl implements View.OnTouchListener {
private boolean movingDownL, movingDownR, movingLeft, movingRight, movingSuccessL, movingSuccessR = false;
private Point oldCoordsL, oldCoordsR, startPointL, startPointR = new Point(0, 0);
private boolean admin_touch = false;
private OnLTouch callback;
public TouchListenerImpl(OnLTouch callback){
setCallback(callback);
}
void setCallback(OnLTouch c) {
callback = c;
}
public interface OnLTouch {
void lTouchSuccess();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("debugTouch", "onTouch");
int pIndexL = event.findPointerIndex(event.getPointerId(0));
int pIndexR = 0;
if(event.getPointerCount() > 1) pIndexR = event.findPointerIndex(event.getPointerId(1));
if(event.getPointerCount() > 1 && event.getX(pIndexL) > event.getX(pIndexR)) {
int tmp = pIndexR;
pIndexR = pIndexL;
pIndexL = tmp;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
movingDownL = true;
movingDownR = true;
movingSuccessL = false;
movingSuccessR = false;
if(event.getPointerCount() > 1) {
startPointR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
oldCoordsR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
}
startPointL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
oldCoordsL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
break;
case MotionEvent.ACTION_MOVE:
int downMinDistance = 300;
int lnrInaccuracy = 10;
int downInaccuracy = 30;
if(event.getPointerCount() > 1) {
if(!movingDownR) {
if(Math.abs(oldCoordsR.x - event.getX(pIndexR)) < downInaccuracy &&
oldCoordsR.y < event.getY(pIndexR)) break;
if(Math.abs(oldCoordsR.y - event.getY(pIndexR)) < lnrInaccuracy &&
oldCoordsR.x > event.getX(pIndexR) && !movingRight) {
movingRight = true;
startPointR = new Point(new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR)));
}
} else {
if (Math.abs(oldCoordsR.x - event.getX(pIndexR)) > downInaccuracy ||
oldCoordsR.y < event.getY(pIndexR)) {
movingDownR = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= downMinDistance){
movingDownR = false;
}
}
}
if(!movingDownL) {
if(Math.abs(oldCoordsL.x - event.getX(pIndexL)) < downInaccuracy &&
oldCoordsL.y < event.getY(pIndexL)) break;
if(Math.abs(oldCoordsL.y - event.getY(pIndexL)) < lnrInaccuracy &&
oldCoordsL.x < event.getX(pIndexL) && !movingLeft) {
movingLeft = true;
startPointL = new Point(new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL)));
}
}else {
if (Math.abs(oldCoordsL.x - event.getX(pIndexL)) > downInaccuracy ||
oldCoordsL.y > event.getY(pIndexL)) {
movingDownL = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= downMinDistance){
movingDownL = false;
}
}
int lnrMinDistance = 50;
if(movingLeft) {
if (Math.abs(oldCoordsL.y - event.getY(pIndexL)) > lnrInaccuracy ||
oldCoordsL.x > event.getX(pIndexL)) {
movingLeft = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= lnrMinDistance) {
movingLeft = false;
movingSuccessL = true;
}
}
if(movingRight) {
if (Math.abs(oldCoordsR.y - event.getY(pIndexR)) > lnrInaccuracy ||
oldCoordsR.x < event.getX(pIndexR)) {
movingRight = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= lnrMinDistance) {
movingRight = false;
movingSuccessR = true;
}
}
if(movingSuccessL && movingSuccessR) {
if (!admin_touch)
{
admin_touch = true;
if (callback != null)
callback.lTouchSuccess();
}
}
oldCoordsL = new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL));
oldCoordsR = new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR));
break;
case MotionEvent.ACTION_UP:
movingDownL = false;
movingDownR = false;
movingLeft = false;
movingRight = false;
break;
default:
return false;
}
return true;
}
private double findDistance(Point p1, Point p2) {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
}
И использование этого:
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.activity_splash);
layout.setOnTouchListener(new TouchListenerImpl(new TouchListenerImpl.OnLTouch() {
@Override
public void lTouchSuccess() {
Toast.makeText(getThis(), "L touched!", Toast.LENGTH_SHORT).show();
}
}));
}
public AppCompatActivity getThis(){
return this;
}
}
Как я уже говорил, причина, по которой вы не получаете никаких журналов, может быть вашей иерархией. Убедитесь, что ваши события касания не используются другими видами сверху. Чтобы быть в самой безопасной, вы должны использовать FrameLayout в качестве корневого элемента для такого поведения и логическую переменную, которая позволяет вам решить, использовать ли L-слушатель или нет.
Проверьте это для дальнейшей справки:
https://github.com/fcopardo/EnhancedMapView
Если вы проверите файл EnhancedMapView, вы найдете следующее:
public void setOnEnhancedCameraChangeListener(OnEnhancedCameraChangeListener listener){
if(map!=null){
map.setOnCameraChangeListener(camera -> {
if(!isContentTouched() && !isCaptureTouches()){
listener.onCameraChange(camera);
}
});
}
}
Это очень похоже на то, что вы делаете. Я предлагаю вам использовать аналогичный подход, подкласс фрейма, реализующий ваш L-touch-слушатель, а затем используйте такой макет, как класс root для ваших представлений и действий. Дайте мне знать, если это поможет.