Страницы

Поиск по вопросам

Показаны сообщения с ярлыком ontouchlistener. Показать все сообщения
Показаны сообщения с ярлыком ontouchlistener. Показать все сообщения

вторник, 17 марта 2020 г.

Android: Как на кнопке одновременно задействовать два сушателя

#java #android #android_on_click #ontouchlistener


Возникла следующая проблема:

Имеется кнопка у которой необходимо обрабатывать два слушателя. Первый это onTouchListener,
второй onClickListener. Код слушателя onTouchListener() ниже:

OnTouchListener dragt = new OnTouchListener()
     {
        @Override
        public boolean onTouch(View v, MotionEvent event) 
        {
            FrameLayout.LayoutParams par = (LayoutParams) v.getLayoutParams();
            switch(v.getId())
            {
                case R.id.button1:

                {
                    switch(event.getAction())
                    {
                        case MotionEvent.ACTION_MOVE:
                        {
                            par.topMargin = (int)event.getRawY() - (v.getHeight());
                            par.leftMargin = (int)event.getRawX() - (v.getWidth()/2);
                            par.bottomMargin = (int)event.getRawX() - (v.getWidth()/2);
                            par.rightMargin = (int)event.getRawX() - (v.getWidth()/2);
                            v.setLayoutParams(par);
                            break;
                        }
                        case MotionEvent.ACTION_UP:
                        {
                            par.height = 120;
                            par.width = 120;
                            par.topMargin = (int)event.getRawY() - (v.getHeight());
                            par.leftMargin = (int)event.getRawX() - (v.getWidth()/2);
                            par.bottomMargin = (int)event.getRawX() - (v.getWidth()/2);
                            par.rightMargin = (int)event.getRawX() - (v.getWidth()/2);
                            v.setLayoutParams(par);
                            break;
                        }
                        case MotionEvent.ACTION_DOWN:
                        {
                            par.height = 150;
                            par.width = 150;
                            v.setLayoutParams(par);
                            break;
                        }
                    }
                    break;
                }
            }
            return true;
        }
     };


Мне же необходимо чтобы при обычном клике срабатывал onClick(). Назначал слушателя
onClickListener - не работает(то есть онтач срабатывает, а онклик нет), назначал кнопке
свойство 
    android:onClick="knopka"

Далее вызывал в активити:

public void knopka(View v) {
       System.out.println("Работай же!!!");
    }


Все равно не работает. Как еще сделать не представляю!
    


Ответы

Ответ 1



Как обычно, читаем документацию: Returns True if the listener has consumed the event, false otherwise. Таким образом, как нетрудно догадаться, вам нужно возвращать из OnTouchListener.onTouch false, а не true.

суббота, 8 февраля 2020 г.

OnTouchListener не работает

#android #camera #ontouchlistener


Не работает данный кусок кода, не могу понять почему.
sv- это SurfaceView, которое используется для отображения камеры(это для заметки).

sv.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                    Toast.makeText(MainActivity.this, "onTouch", Toast.LENGTH_SHORT).show();
                    return true;}}});

    


Ответы

Ответ 1



Попробуйте другое событие. sv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(View.getContext(), "Clicked", Toast.LENGTH_SHORT).show(); Log.v("W", "Clicked"); });

Ответ 2



Делал список на основе ListView. Нужны были свайпы, скрол и *синглтачи*. Не хотелось использовать или кастомить никакие GestureDetector-ы. Но одновременное вешание нескольких *листенеров* на одну вьюху заканчивалось только тем что приходилось делать костыли которые намного тяжелее чем любой GestureDetector. Потому, пришлось повесить на вьюху OnTouchListener, из метода onTouch передавать событие касания в GestureDetectorCompat, и уже в его методе onScroll реализовал саму логику *свайпа*. *Синглтачи* обрабатывал средствами того же `GestureDetectorCompat.

пятница, 24 января 2020 г.

Android, вызов onTouchListener только внутри view

#android #ontouchlistener


Имеется кнопка, с прикрепленным onTouchListener. Если я нажимаю кнопку и двигаю палец
за границы кнопки, то onTouchListener всё равно вызывается. Как можно поменять это
поведение, чтобы обработчик не вызывался за пределами View, к которому он прикреплен?

Сделал скриншот проблемы, которую пытаюсь решить. Когда я нажимаю палецем и двигаю
им к нижней части экрана, то после определенной черты при опускании второго пальца
координаты странным образом "прыгают", а мне нужна точная обработка касания в зеленых
границах, без мультитачей и выхода за зеленые границы


    


Ответы

Ответ 1



Вам надо переопределить onTouchEvent для корневого View следующим образом (тем самым вы будете игнорировать мультитач в пределах этого View): @Override public boolean onTouchEvent(MotionEvent event) { if(event.getPointerCount() > 1) //если определили второе и более касание, игнорируем его return true; else return super.onTouchEvent(event); }

понедельник, 6 января 2020 г.

Новая строка в ListView при добавлении с БД, принимает значения ранее удаленной

#android #listview #animate #ontouchlistener


Есть список на основе ListView и SimpleCursorAdapter и SQLite.  

Пишу Swipe строки списка с помощью анимации. В ACTION_MOVE строка списка должна двигаться
влево за пальцем и при достижении определенного значения по оси X менять цвет и ставать
доступной для удаления. В этой зоне при ACTION_UP строка должна удалиться с БД по найденому
ID. Соответствующе в перерисованом ListView строка с удаляемой позицией исчезает из
списка на экране.  Все это работает, но возникает следующая проблемма:

При добавлении в БД новой строки она появляется в списке на экране в том состоянии
и в том положении по оси X которое было у ранее удаленной строки.

Предполагаю что, скорее всего, где-то ListView держит ранее использованные вьюхи
с теми характеристиками с которыми они были ранее удалены и заливает туда новые строки
с БД.

Пробовал применять после удаления: notifyDataSetChanged(), завершение анимации -
эффекта нет.

    public class MainActivity extends AppCompatActivity implements View.OnClickListener,
    View.OnTouchListener, LoaderManager.LoaderCallbacks {

DB db;
DBHelper dbHelper;
SimpleCursorAdapter scAdapter;
Context context;
String name;
String kind;

private View onTouchedItemView;

ListView lv_list;
Button btnEmpty, btnAdd, btnRead, btnClear;
TextView tvNameId, tvNameName, tvNameKind, tvNameCost;
EditText tvName, tvKind;

private int pointDownX;
private int pointDownY;
private long touchedItemID;

private int targetPoint;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    db = new DB(this);
    db.open();

    String[] from = new String[]{DB.KEY_ID, DB.KEY_NAME, DB.KEY_KIND, DB.KEY_COST};
    int[] to = new int[]{R.id.tvListId, R.id.tvListName, R.id.tvListKind, R.id.tvListCost};

    scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);

    lv_list = (ListView) findViewById(R.id.lv_list);
    lv_list.setAdapter(scAdapter);

    lv_list.setOnTouchListener(this);
    getSupportLoaderManager().initLoader(0, null, this);

    tvNameId = (TextView) findViewById(R.id.tvNameId);
    tvNameName = (TextView) findViewById(R.id.tvNameName);
    tvNameKind = (TextView) findViewById(R.id.tvNameKind);
    tvNameCost = (TextView) findViewById(R.id.tvNameCost);

    tvName = (EditText) findViewById(R.id.tvName);
    tvName.setOnClickListener(this);

    tvKind = (EditText) findViewById(R.id.tvKind);
    tvKind.setOnClickListener(this);

    btnAdd = (Button) findViewById(R.id.btnAdd);
    btnAdd.setOnClickListener(this);

    btnEmpty = (Button) findViewById(R.id.btnEmpty);
    btnEmpty.setOnClickListener(this);

    btnRead = (Button) findViewById(R.id.btnRead);
    btnRead.setOnClickListener(this);

    btnClear = (Button) findViewById(R.id.btnClear);
    btnClear.setOnClickListener(this);
}

@Override
public void onClick(View view) {
    name = tvName.getText().toString();
    kind = tvKind.getText().toString();

    switch (view.getId()) {
        case R.id.btnAdd:
            if (kind.isEmpty()) {
                kind = "1";
            }
            if (name.isEmpty()) {
                Toast.makeText(getApplicationContext(),
                        "Fill all fields", Toast.LENGTH_SHORT).show();
            } else {
                db.addRec(name, kind);
                getSupportLoaderManager().getLoader(0).forceLoad();
                tvName.setText("");
                tvKind.setText("");
            }
            break;

        case R.id.btnEmpty:
            tvName.setText("");
            tvKind.setText("");
            break;

        case R.id.btnRead:
            getSupportLoaderManager().getLoader(0).forceLoad();
            break;

        case R.id.btnClear:
            db.delAllRec();
            getSupportLoaderManager().getLoader(0).forceLoad();
            break;
    }
}

@Override
public Loader onCreateLoader(int id, Bundle bndl) {
    return new MyCursorLoader(this, db);
}

@Override
public void onLoadFinished(Loader loader, Cursor cursor) {
    scAdapter.swapCursor(cursor);
}

@Override
public void onLoaderReset(Loader loader) {
}


@Override
public boolean onTouch(View v, MotionEvent event) {

    int dispWidth = v.getWidth();
    int horizontalMinDistance = dispWidth / 4;
    int distFromRightBorder = dispWidth - pointDownX;
    int distToMeet = pointDownX / 10;

    switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:
            pointDownX = (int) event.getX();
            pointDownY = (int) event.getY();

            onTouchedItemView = lv_list.getChildAt(lv_list.pointToPosition(pointDownX,
pointDownY));
            touchedItemID = lv_list.pointToRowId(pointDownX, pointDownY);

            return true;

        case MotionEvent.ACTION_MOVE:
            int pointMovingX = (int) event.getX();
            int deltaX = pointDownX - pointMovingX;

            int distGone = distFromRightBorder / distToMeet * Math.abs(deltaX);

            if (deltaX < 0) {

                if (Math.abs(deltaX) < distToMeet) {
                    targetPoint = dispWidth - pointMovingX + pointDownX - distGone;

                } else {
                    targetPoint = pointMovingX;


                }
                anim();

            } else {

                if (Math.abs(deltaX) < distToMeet) {
                    targetPoint = pointMovingX - dispWidth + distFromRightBorder
- distGone;

                } else {
                    targetPoint = pointMovingX - dispWidth;

                    if (Math.abs(deltaX) > horizontalMinDistance && pointMovingX
< dispWidth / 8) {
                        onTouchedItemView.setBackgroundResource(R.color.deletemarker);

                    } else {
                        onTouchedItemView.setBackgroundResource(R.color.backgroundmain);
                    }
                }
                anim();
            }
            return true;

        case MotionEvent.ACTION_UP:
            float upX = (int) event.getRawX();

            if (upX < dispWidth / 8) {


                db.delRec(touchedItemID);


                getSupportLoaderManager().getLoader(0).forceLoad();

            } else {
                targetPoint = 0;
                anim();
            }
            return true;
    }
    return true;
}

public void anim() {
    onTouchedItemView.animate()
            .x(targetPoint)
            .setDuration(0)
            .start();
}

private static class MyCursorLoader extends CursorLoader {
    DB db;

    public MyCursorLoader(Context context, DB db) {
        super(context);
        this.db = db;
    }

    @Override
    public Cursor loadInBackground() {
        Cursor cursor = db.getAllData();
        return cursor;
    }
}

protected void onDestroy() {
    super.onDestroy();
    db.close();
}
}



    


Ответы

Ответ 1



Нашел решение. Применил обратную анимацию перед обновлением списка. onTouchedItemView.setBackgroundResource(R.color.backgroundmain); targetPoint = 0; anim(); И метод: clearDisappearingChildren(); Он удаляет анимацию на удаленном элементе списка. В коде выглядит так: case MotionEvent.ACTION_UP: float upX = (int) event.getRawX(); if (upX < dispWidth / 8) { db.delRec(touchedItemID); lv_list.clearDisappearingChildren(); getSupportLoaderManager().getLoader(0).forceLoad(); onTouchedItemView.setBackgroundResource(R.color.backgroundmain); targetPoint = 0; anim(); } else { targetPoint = 0; anim(); } return true;

вторник, 31 декабря 2019 г.

Разные действия Click, LongClick и Touch на одно и то же место

#java #android #android_on_click #ontouchlistener


Есть определенные сомнения, но все таки вдруг такое поведение возможно.
Суть: у меня есть FrameLayout (отсюда) с событием onTouch для зуминга. В этом Frame
есть несколько элементов, которые принимают события onClick и onLongClick:

for (int i = 0; i < locations.size(); i++) {
        locations.get(i).getView().setOnClickListener(onPoleClick);
        locations.get(i).getView().setOnLongClickListener(onPoleLongClick);
}


если я выставляю слушателя на клик - перестает действовать MyFrame.onTouch и поле
не зумится. Если убираю - соответственно, сижу без кликов, но с зумящимся полем. Если
ставлю return false; в MyFrame.onTouch, он также перестает работать.
Пробовал заменить locations.get(i).onClick на onTouch (MotionEvent.UP) - при return
true клик до Frame не доходит, при return false MotionEvent.UP не срабатывает. MotionEvent.DOWN
не даст обработать onLongClick...

Дудочка и кувшинчик, в общем. Может быть есть какой-то способ, чтобы onTouch срабатывал
"сквозь" клики?
    


Ответы

Ответ 1



Можно попробовать вот так: public class ZoomFrameLayout extends FrameLayout { public ZoomFrameLayout(Context context) { super(context); } public ZoomFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public ZoomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean upper = super.onInterceptTouchEvent(ev); if (!upper) { // Детектим жесты здесь стандартным детектором // и если зум - отрабатываем и выставляем return true } return upper; } } Т.е. вид ZoomFrameLayout будет забирать себе только зум, а клики уйдут детишкам. И кстати при таком использовании ScaleDetector будут все события перехватываться (там return true в конце). Можно попробовать что-нибуть вроде if (scaleDetector.isInProgress()) return true;

Ответ 2



Просто совместите оба действия в onTouch: private int min=50; private int x, dx; public boolean onTouch(View v, MotionEvent event) { if(event.getAction()==MotionEvent.ACTION_DOWN) { x = event.getX(); } else if(event.getAction()==MotionEvent.ACTION_UP) { dx = event.getX(); if (Math.abs( dx - x ) > min) { // зум } else { // клик } } }

четверг, 26 декабря 2019 г.

OnTouchListener у Layout

#android #android_sdk #разметка #ontouchlistener




Имеется два Layout:

A - RelativeLayout.
B - LinearLayout.

Вот пример разметки:




    

        

        
        



На  Layout A я установил слушатель OnTouchListener. Мне нужно, чтобы при нажатии
на область Layout B или на его потомков, слушатель не срабатывал, а при касании за
границей Layout A срабатывал. 

При нажатии на Spinner слушатель Layout A не срабатывает, т.к. на нем (спиннере)
есть свой родной слушатель, однако у View его нет. Установить на него слушатель не
вариант. Что делать?
    


Ответы

Ответ 1



Добавьте OnTouchListener для Layout B и в нём устанавливайте значение булевой переменной, а в OnTouchListener для Layout A проверяйте значение этой переменной. Например, так: boolean ChildTouched = false; RelativeLayout ParentLayout = (RelativeLayout)findViewById(R.id.menuParentLayout); ParentLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (ChildTouched) { ChildTouched = false; return true; } System.out.println("Touch parent activity"); return true; } }); LinearLayout ChildLayout = (LinearLayout)findViewById(R.id.menuLayout); ChildLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { System.out.println("Touch child activity"); ChildTouched = true; return true; } });

четверг, 11 июля 2019 г.

Перемещающаяся кнопка, как сделать OnClick?

Всем доброго времени суток!
Пусть есть любой View (для примера, кнопка), который должен постоянно двигаться и, в случае клика по нему, вызывать обработчик onclick. Я так полагаю, что если двигать кнопку, используя translate-анимацию, то кликнуть по ней можно будет только в том месте, откуда она начала движение, или в том, где прекратила движение.
Так не пойдет, нужно, чтоб в любом участке ее пути она была кликабельна там, где находится в конкретный момент. Можно заставить кнопку двигаться в цикле, изменяя ее X-, Y-координаты. Но тогда, я так полагаю, если зажать кнопку и подождать, пока она выйдет из под пальца в результате своей анимации, обработчик клика все равно сработает (или не сработает?). Нужно, чтоб он срабатывал только в случае, если палец был поднят от экрана в том же месте, где в это мгновение находится кнопка.
Как это реализовать, я не знаю, может, посоветуете пути решения?
В результате ответ, данный ниже, оказался правильным, вот реализация проверки, не ушла ли кнопка из-под пальца, если кому надо:
Я повесил на кнопку onTouchListener, и вот его код (isOff на входе =false):
case MotionEvent.ACTION_DOWN: firsttapX = motionEvent.getX();//берем Х и Y куда ткнули пальцем( по кнопке) firsttapY = motionEvent.getY(); break; case MotionEvent.ACTION_MOVE: if (isOff==false) { dx = motionEvent.getX() - firsttapY;//получаем разницу между текущим dy = motionEvent.getY() - firsttapX;//положением кнопки и точкой куда мы if (abs(dx) > 50 || abs(dy) > 50) {//нажали isOf=true; /*тут то, что я хотел реализовать по клику мимо кнопки или если она свалила из-под пальца, это же продублировано в onClick мимо кнопки*/ } } break;
Если разница больше определенного числа (размер кнопки), то кнопка не под пальцем isOff=true перестает обрабатывать ACTION_MOVE.


Ответ

Если использовать ObjectAnimator, то кликнуть по ней можно будет и в момент движения. Но это только для API 11+

четверг, 6 июня 2019 г.

Android: Как на кнопке одновременно задействовать два сушателя

Возникла следующая проблема:
Имеется кнопка у которой необходимо обрабатывать два слушателя. Первый это onTouchListener, второй onClickListener. Код слушателя onTouchListener() ниже:
OnTouchListener dragt = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { FrameLayout.LayoutParams par = (LayoutParams) v.getLayoutParams(); switch(v.getId()) { case R.id.button1:
{ switch(event.getAction()) { case MotionEvent.ACTION_MOVE: { par.topMargin = (int)event.getRawY() - (v.getHeight()); par.leftMargin = (int)event.getRawX() - (v.getWidth()/2); par.bottomMargin = (int)event.getRawX() - (v.getWidth()/2); par.rightMargin = (int)event.getRawX() - (v.getWidth()/2); v.setLayoutParams(par); break; } case MotionEvent.ACTION_UP: { par.height = 120; par.width = 120; par.topMargin = (int)event.getRawY() - (v.getHeight()); par.leftMargin = (int)event.getRawX() - (v.getWidth()/2); par.bottomMargin = (int)event.getRawX() - (v.getWidth()/2); par.rightMargin = (int)event.getRawX() - (v.getWidth()/2); v.setLayoutParams(par); break; } case MotionEvent.ACTION_DOWN: { par.height = 150; par.width = 150; v.setLayoutParams(par); break; } } break; } } return true; } };
Мне же необходимо чтобы при обычном клике срабатывал onClick(). Назначал слушателя onClickListener - не работает(то есть онтач срабатывает, а онклик нет), назначал кнопке свойство android:onClick="knopka"
Далее вызывал в активити:
public void knopka(View v) { System.out.println("Работай же!!!"); }
Все равно не работает. Как еще сделать не представляю!


Ответ

Как обычно, читаем документацию Returns True if the listener has consumed the event, false otherwise. Таким образом, как нетрудно догадаться, вам нужно возвращать из OnTouchListener.onTouch false, а не true

вторник, 19 марта 2019 г.

Android, вызов onTouchListener только внутри view

Имеется кнопка, с прикрепленным onTouchListener. Если я нажимаю кнопку и двигаю палец за границы кнопки, то onTouchListener всё равно вызывается. Как можно поменять это поведение, чтобы обработчик не вызывался за пределами View, к которому он прикреплен?
Сделал скриншот проблемы, которую пытаюсь решить. Когда я нажимаю палецем и двигаю им к нижней части экрана, то после определенной черты при опускании второго пальца координаты странным образом "прыгают", а мне нужна точная обработка касания в зеленых границах, без мультитачей и выхода за зеленые границы


Ответ

Вам надо переопределить onTouchEvent для корневого View следующим образом (тем самым вы будете игнорировать мультитач в пределах этого View):
@Override public boolean onTouchEvent(MotionEvent event) {
if(event.getPointerCount() > 1) //если определили второе и более касание, игнорируем его return true; else return super.onTouchEvent(event); }

вторник, 12 февраля 2019 г.

Новая строка в ListView при добавлении с БД, принимает значения ранее удаленной

Есть список на основе ListView и SimpleCursorAdapter и SQLite.
Пишу Swipe строки списка с помощью анимации. В ACTION_MOVE строка списка должна двигаться влево за пальцем и при достижении определенного значения по оси X менять цвет и ставать доступной для удаления. В этой зоне при ACTION_UP строка должна удалиться с БД по найденому ID. Соответствующе в перерисованом ListView строка с удаляемой позицией исчезает из списка на экране. Все это работает, но возникает следующая проблемма:
При добавлении в БД новой строки она появляется в списке на экране в том состоянии и в том положении по оси X которое было у ранее удаленной строки.
Предполагаю что, скорее всего, где-то ListView держит ранее использованные вьюхи с теми характеристиками с которыми они были ранее удалены и заливает туда новые строки с БД.
Пробовал применять после удаления: notifyDataSetChanged(), завершение анимации - эффекта нет.
public class MainActivity extends AppCompatActivity implements View.OnClickListener, View.OnTouchListener, LoaderManager.LoaderCallbacks {
DB db; DBHelper dbHelper; SimpleCursorAdapter scAdapter; Context context; String name; String kind;
private View onTouchedItemView;
ListView lv_list; Button btnEmpty, btnAdd, btnRead, btnClear; TextView tvNameId, tvNameName, tvNameKind, tvNameCost; EditText tvName, tvKind;
private int pointDownX; private int pointDownY; private long touchedItemID;
private int targetPoint;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
db = new DB(this); db.open();
String[] from = new String[]{DB.KEY_ID, DB.KEY_NAME, DB.KEY_KIND, DB.KEY_COST}; int[] to = new int[]{R.id.tvListId, R.id.tvListName, R.id.tvListKind, R.id.tvListCost};
scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);
lv_list = (ListView) findViewById(R.id.lv_list); lv_list.setAdapter(scAdapter);
lv_list.setOnTouchListener(this); getSupportLoaderManager().initLoader(0, null, this);
tvNameId = (TextView) findViewById(R.id.tvNameId); tvNameName = (TextView) findViewById(R.id.tvNameName); tvNameKind = (TextView) findViewById(R.id.tvNameKind); tvNameCost = (TextView) findViewById(R.id.tvNameCost);
tvName = (EditText) findViewById(R.id.tvName); tvName.setOnClickListener(this);
tvKind = (EditText) findViewById(R.id.tvKind); tvKind.setOnClickListener(this);
btnAdd = (Button) findViewById(R.id.btnAdd); btnAdd.setOnClickListener(this);
btnEmpty = (Button) findViewById(R.id.btnEmpty); btnEmpty.setOnClickListener(this);
btnRead = (Button) findViewById(R.id.btnRead); btnRead.setOnClickListener(this);
btnClear = (Button) findViewById(R.id.btnClear); btnClear.setOnClickListener(this); }
@Override public void onClick(View view) { name = tvName.getText().toString(); kind = tvKind.getText().toString();
switch (view.getId()) { case R.id.btnAdd: if (kind.isEmpty()) { kind = "1"; } if (name.isEmpty()) { Toast.makeText(getApplicationContext(), "Fill all fields", Toast.LENGTH_SHORT).show(); } else { db.addRec(name, kind); getSupportLoaderManager().getLoader(0).forceLoad(); tvName.setText(""); tvKind.setText(""); } break;
case R.id.btnEmpty: tvName.setText(""); tvKind.setText(""); break;
case R.id.btnRead: getSupportLoaderManager().getLoader(0).forceLoad(); break;
case R.id.btnClear: db.delAllRec(); getSupportLoaderManager().getLoader(0).forceLoad(); break; } }
@Override public Loader onCreateLoader(int id, Bundle bndl) { return new MyCursorLoader(this, db); }
@Override public void onLoadFinished(Loader loader, Cursor cursor) { scAdapter.swapCursor(cursor); }
@Override public void onLoaderReset(Loader loader) { }
@Override public boolean onTouch(View v, MotionEvent event) {
int dispWidth = v.getWidth(); int horizontalMinDistance = dispWidth / 4; int distFromRightBorder = dispWidth - pointDownX; int distToMeet = pointDownX / 10;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: pointDownX = (int) event.getX(); pointDownY = (int) event.getY();
onTouchedItemView = lv_list.getChildAt(lv_list.pointToPosition(pointDownX, pointDownY)); touchedItemID = lv_list.pointToRowId(pointDownX, pointDownY);
return true;
case MotionEvent.ACTION_MOVE: int pointMovingX = (int) event.getX(); int deltaX = pointDownX - pointMovingX;
int distGone = distFromRightBorder / distToMeet * Math.abs(deltaX);
if (deltaX < 0) {
if (Math.abs(deltaX) < distToMeet) { targetPoint = dispWidth - pointMovingX + pointDownX - distGone;
} else { targetPoint = pointMovingX;
} anim();
} else {
if (Math.abs(deltaX) < distToMeet) { targetPoint = pointMovingX - dispWidth + distFromRightBorder - distGone;
} else { targetPoint = pointMovingX - dispWidth;
if (Math.abs(deltaX) > horizontalMinDistance && pointMovingX < dispWidth / 8) { onTouchedItemView.setBackgroundResource(R.color.deletemarker);
} else { onTouchedItemView.setBackgroundResource(R.color.backgroundmain); } } anim(); } return true;
case MotionEvent.ACTION_UP: float upX = (int) event.getRawX();
if (upX < dispWidth / 8) {
db.delRec(touchedItemID);
getSupportLoaderManager().getLoader(0).forceLoad();
} else { targetPoint = 0; anim(); } return true; } return true; }
public void anim() { onTouchedItemView.animate() .x(targetPoint) .setDuration(0) .start(); }
private static class MyCursorLoader extends CursorLoader { DB db;
public MyCursorLoader(Context context, DB db) { super(context); this.db = db; }
@Override public Cursor loadInBackground() { Cursor cursor = db.getAllData(); return cursor; } }
protected void onDestroy() { super.onDestroy(); db.close(); } }


Ответ

Нашел решение.
Применил обратную анимацию перед обновлением списка.
onTouchedItemView.setBackgroundResource(R.color.backgroundmain); targetPoint = 0; anim();
И метод:
clearDisappearingChildren();
Он удаляет анимацию на удаленном элементе списка.
В коде выглядит так:
case MotionEvent.ACTION_UP:
float upX = (int) event.getRawX();
if (upX < dispWidth / 8) {
db.delRec(touchedItemID);
lv_list.clearDisappearingChildren();
getSupportLoaderManager().getLoader(0).forceLoad(); onTouchedItemView.setBackgroundResource(R.color.backgroundmain); targetPoint = 0; anim();
} else {
targetPoint = 0; anim();
} return true;

вторник, 25 декабря 2018 г.

Разные действия Click, LongClick и Touch на одно и то же место

Есть определенные сомнения, но все таки вдруг такое поведение возможно. Суть: у меня есть FrameLayout (отсюда) с событием onTouch для зуминга. В этом Frame есть несколько элементов, которые принимают события onClick и onLongClick:
for (int i = 0; i < locations.size(); i++) { locations.get(i).getView().setOnClickListener(onPoleClick); locations.get(i).getView().setOnLongClickListener(onPoleLongClick); }
если я выставляю слушателя на клик - перестает действовать MyFrame.onTouch и поле не зумится. Если убираю - соответственно, сижу без кликов, но с зумящимся полем. Если ставлю return false; в MyFrame.onTouch, он также перестает работать. Пробовал заменить locations.get(i).onClick на onTouch (MotionEvent.UP) - при return true клик до Frame не доходит, при return false MotionEvent.UP не срабатывает. MotionEvent.DOWN не даст обработать onLongClick...
Дудочка и кувшинчик, в общем. Может быть есть какой-то способ, чтобы onTouch срабатывал "сквозь" клики?


Ответ

Можно попробовать вот так:
public class ZoomFrameLayout extends FrameLayout { public ZoomFrameLayout(Context context) { super(context); }
public ZoomFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); }
public ZoomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean upper = super.onInterceptTouchEvent(ev); if (!upper) { // Детектим жесты здесь стандартным детектором // и если зум - отрабатываем и выставляем return true } return upper; } }
Т.е. вид ZoomFrameLayout будет забирать себе только зум, а клики уйдут детишкам.
И кстати при таком использовании ScaleDetector будут все события перехватываться (там return true в конце). Можно попробовать что-нибуть вроде if (scaleDetector.isInProgress()) return true;

четверг, 29 ноября 2018 г.

OnTouchListener у Layout


Имеется два Layout:
A - RelativeLayout. B - LinearLayout.
Вот пример разметки:




На Layout A я установил слушатель OnTouchListener. Мне нужно, чтобы при нажатии на область Layout B или на его потомков, слушатель не срабатывал, а при касании за границей Layout A срабатывал.
При нажатии на Spinner слушатель Layout A не срабатывает, т.к. на нем (спиннере) есть свой родной слушатель, однако у View его нет. Установить на него слушатель не вариант. Что делать?


Ответ

Добавьте OnTouchListener для Layout B и в нём устанавливайте значение булевой переменной, а в OnTouchListener для Layout A проверяйте значение этой переменной. Например, так:
boolean ChildTouched = false; RelativeLayout ParentLayout = (RelativeLayout)findViewById(R.id.menuParentLayout); ParentLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (ChildTouched) { ChildTouched = false; return true; } System.out.println("Touch parent activity"); return true; } });
LinearLayout ChildLayout = (LinearLayout)findViewById(R.id.menuLayout); ChildLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { System.out.println("Touch child activity"); ChildTouched = true; return true; } });