Кнопка перетаскивания выходит за пределы экрана?

У меня есть одна кнопка и я могу перетаскивать ее куда угодно на экране, но она при перетаскивании выходит за пределы экрана, так как же перетаскивать только внутри экрана, чтобы она не выходила за пределы экрана

Button.setOnTouchListener(new TextView.OnTouchListener() {
        public boolean onTouch(View view, MotionEvent event) {              

            X_button = (int) event.getRawX();
            Y_button= (int) event.getRawY();


            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:

                RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                _xDelta = X_button - lParams.leftMargin;
                _yDelta = Y_button - lParams.topMargin;
                break;
            case MotionEvent.ACTION_UP:                 
                 if(!isMoving)
                 {
                    view.performClick();                        
                 }  

                 isMoving=false;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
            case MotionEvent.ACTION_MOVE:                   
                isMoving=true;                  
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
                        .getLayoutParams();
                layoutParams.leftMargin = X_button - _xDelta;
                layoutParams.topMargin = Y_button - _yDelta;
                layoutParams.rightMargin = -250;
                layoutParams.bottomMargin = -250;
                view.setLayoutParams(layoutParams);

                break;
            }
            return true;
        }
    });

person sachin    schedule 25.02.2014    source источник


Ответы (3)


Во-первых, используйте методы View.setX(), View.setY(), View.setTranslateX(), View.setTranslateY() для перемещения представлений на экране вместо обновления полей LayoutParams. Я обнаружил, что они работают более плавно.

Во-вторых, для ограничения представлений доступным окном получите доступный размер окна, используя следующую функцию:

DisplayMetrics metrics = getResources().getDisplayMetrics();
int windowWidth = metrics.widthPixels;
int windowHeight = metrics.heightPixels

Затем в методе onTouch вычислите, превышает ли целевое местоположение вышеуказанные размеры. Например:

if( currentXLocation + deltaX > windowWidth ){

    // this will ensure that target location 
    // is always <= windowHeight
    deltaX = windowWidth - currentXLocation; 

} else if( currentXLocation + deltaX < 0){

    deltaX = -(currentXLocation);

} else if (...){

    // perform similar calculations for the rest 

}
person Saket    schedule 25.02.2014
comment
спасибо за ответ ..... где я должен сделать это, если и еще, если? в MotionEvent.Action_Move? Пожалуйста, объясните мне подробно, так как я новичок в Android. а при чем здесь deltaX? - person sachin; 26.02.2014
comment
если я удалю layoutParams.rightMargin = -250; layoutParams.bottomMargin = -250; эти две мои кнопки не будут выходить за пределы экрана внизу и справа, но моя кнопка будет уменьшаться при перетаскивании вниз и вправо - person sachin; 26.02.2014
comment
Привет Сачин, да, вам нужно поместить эти условия If/Else в ваш ACTION_MOVE случай. И я не получил ваш второй вопрос о полях макета. Не могли бы вы уточнить? - person Saket; 26.02.2014
comment
спасибо, я поместил его в ACTION_MOVE, и я применил другую логику, и это сработало - person sachin; 26.02.2014

Измените раздел прослушивателя OnTouch как:

 DisplayMetrics displaymetrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
 screenHight = displaymetrics.heightPixels;
 screenWidth = displaymetrics.widthPixels;

  @SuppressLint("NewApi") @Override
  public boolean onTouch(View view, MotionEvent event) {


       float newX, newY;

    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:

        dX = view.getX() - event.getRawX();
        dY = view.getY() - event.getRawY();
        lastAction = MotionEvent.ACTION_DOWN;
        break;

      case MotionEvent.ACTION_MOVE:

          newX = event.getRawX() + dX;
          newY = event.getRawY() + dY;

      // check if the view out of screen
          if ((newX <= 0 || newX >= screenWidth-view.getWidth()) || (newY <= 0 || newY >= screenHight-view.getHeight()))
          {
              lastAction = MotionEvent.ACTION_MOVE;
              break;      
          }

        view.setX(newX);
        view.setY(newY);

        lastAction = MotionEvent.ACTION_MOVE;

        break;

      case MotionEvent.ACTION_UP:
        if (lastAction == MotionEvent.ACTION_DOWN)
          Toast.makeText(DraggableView.this, "Clicked!", Toast.LENGTH_SHORT).show();
        break;

      default:
        return false;
    }
    return true;
  }

Обратитесь к этому решению, при перетаскивании изображение остается на экране. https://stackoverflow.com/a/36417605/4324288

person Amal Dev S I    schedule 05.04.2016

Зарегистрировался только для того, чтобы ответить на этот вопрос из-за разочарования от того, что нашел один и тот же, к сожалению, неправильный ответ по всему Интернету.

Чтобы обработать ваш объект, отрисовываемый за пределами представления, настройте OnDragListener для объекта, затем вызовите обработчик оттуда — он выйдет из строя, если вы не используете обработчик — и передайте идентификатор представления обработчику. Кроме того, я обнаружил, что ваш пользователь также может испортить работу, нажав две кнопки в одно и то же время, и когда вы переключаете действия, если пользователь касается экрана, вы также можете потерять объекты таким образом - так что лучше всего сработало то, что мой обработчик вызывается из прослушивателя перетаскивания ACTION_DRAG_ENDED, а прослушиватель касания ACTION_UP просто следит за тем, чтобы все, что должно быть видно, было видимым. Таким образом, каждый раз, когда пользователь перестает касаться экрана, он исправит все, что он сделал.

private final class MyTouchListener implements OnTouchListener {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                ClipData data = ClipData.newPlainText("", "");
                DragShadowBuilder shadowBuilder = new DragShadowBuilder(view);
                view.startDrag(data, shadowBuilder, view, 0);
                view.setVisibility(View.INVISIBLE);
                return true;
            case MotionEvent.ACTION_UP:
                drophandler.sendEmptyMessage(0);
            case MotionEvent.ACTION_MOVE:
                return true;
            default:
                break;
            }
        return true;
    }
}

class MyDragListener implements OnDragListener {
    @Override
    public boolean onDrag(View v, DragEvent event) {
        View view = (View) event.getLocalState();
        Button drag = (Button) view;
        int action = event.getAction();

        switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                break;
            case DragEvent.ACTION_DROP:
                Button target = (Button) v;
                //do stuff
                return true;
            case DragEvent.ACTION_DRAG_ENDED:
                drophandler.sendEmptyMessage(0);
                return true;
            default:
                break;
        }
        return true;
    }
}

private Handler drophandler = new Handler() {
    public void handleMessage(android.os.Message msg) {
        for(int x = 0; x < 3 + difficulty; x++){
            for(int y = 0; y < 5 + difficulty; y++){
                if (buttons[x][y] != null){
                    buttons[x][y].setVisibility(View.VISIBLE);
                }
            }
        }
    }
};
person houndx    schedule 03.02.2015