마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

레이아웃 확대 축소 질문입니다.

0 추천

현재 윈도우매니저에 리니어레이아웃을 넣고 화면에 띄운뒤

양손가락을 이용해서 확대/축소하는 기능을 시험하고 있습니다

원래는 scalegesturedetector를 이용해서 구현을 했는데 

원하는 방향으로만 커지는게 아니라 비율로 증가하는 형태여서 간단하게 직접 구현해봤습니다

문제는 확대/축소가 상당히 크기가 커졌다 작아졌다하면서 흔들리면서 진행이 되고

가로로는 이동이 되면서 커지지만 세로로는 고정된 상태에서 커지는 이상한 현상이 발생하고 있습니다.

손가락이 움직이는 방향대로 크기가 부드럽게 커지려면 어떤 점을 고쳐야 할까요?

아래는 터치리스너 소스코드입니다.

ll.setOnTouchListener(new View.OnTouchListener() {
  WindowManager.LayoutParams updatedParameters = parameters;

  //updatedParameters.x와 y
  double x,y;

  //x,y 좌표값이 더 작은 인덱스 저장용 변수
  int indexX, indexY;

  //작은 xy 좌표값 저장용 변수
  double posX,posY;

  //손가락 사이의 xy거리 구하기
  int dist0X, dist0Y;

  //움직인 후 손가락 사이의 xy거리
  int dist1X, dist1Y;

  //원래 너비/높이 저장용 변수
  int orgWidth , orgHeight;

  boolean pinch = false;

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

    switch (event.getAction() & MotionEvent.ACTION_MASK) {

        case MotionEvent.ACTION_POINTER_DOWN:

          pinch = true;
          x = updatedParameters.x;
          y = updatedParameters.y;

          //두 손가락 위치 중 작은 x값/y값 좌표를 지닌 인덱스를 얻고 그 좌표값을 각각 저장합니다.
          indexX = event.getX(0) > event.getX(1) ? 1:0;
          indexY = event.getY(0) > event.getY(1) ? 1:0;
          posX = event.getX(indexX);
          posY = event.getY(indexY);

          //두 손가락 사이의 x,y좌표 거리를 구합니다.
          dist0X = (int)(event.getX(1-indexX) - event.getX(indexX));
          dist0Y = (int)(event.getY(1-indexY) - event.getY(indexY));

          //원래 크기 구하기
          orgWidth=v.getMeasuredWidth();
          orgHeight=v.getMeasuredHeight();

          break;

        case MotionEvent.ACTION_MOVE:

          if(pinch){
          //현재 x,y좌표에 가장 좌측/상단의 x/y좌표의 변화 값을 더하여 갱신합니다.
          updatedParameters.x=(int)(x+(event.getX(indexX)-posX));
          updatedParameters.y=(int)(y+(event.getY(indexY)-posY));

 
          //움직인 두 손가락 사이의 x,y좌표 거리를 구합니다.
          dist1X = (int)(event.getX(0) > event.getX(1) ? event.getX(0) - event.getX(1) : event.getX(1) - event.getX(0));
          dist1Y = (int)(event.getY(0) > event.getY(1) ? event.getY(0) - event.getY(1) : event.getY(1) - event.getY(0));

          //움직인 후의 x/y거리와 처음의 x/y거리의 차를 구하고 각 너비/높이의 값을 변경합니다.
         updatedParameters.width = dist1X - dist0X + orgWidth;
          updatedParameters.height = dist1Y - dist0Y + orgHeight;

          //업데이트
          wm.updateViewLayout(ll,updatedParameters);
          }
          break;

       default:
          pinch = false;
          break;
        }
      return false;
    }
});

 

 

날라간다 (220 포인트) 님이 2017년 10월 7일 질문

1개의 답변

0 추천
리니어레이아웃은 Stacked라서 위에서부터 쌓이기 때문에 조절하기가 쉽지 않죠.

따라서 RelativeLayout을 써야 합니다. 이 레이아웃은 겹치기도 합니다. 따라서 뭐가 위에 있느냐에 따라서 맨위에 있는게 보입니다. 레이아웃 xml 파일에서 하단에 정의된 것이 더 위로 올라갑니다.

제가 한다면 두 손가락의 좌표를 x1, y1, x2, y2 라고 가정한다면,

x1과 x2 중 작은 값을 x_left 로 정하고 x_left_idx 에는 x2가 더 작을 경우엔 2를 입력합니다.

똑같이 x_right에 더 큰 값을 입력합니다. x_right_idx는 필요 없겠죠?

그래서 핀치로 이동해서 새로운 x1, x2를 받았으면 아래 로직으로 진행합니다.

어찌되었던 x의 입장에서는 다 원쪽 좌표를 가진 손가락의 차이가 마이너스이면 오른쪽으로 이동했으니 그 이동한 만큼 width를 줄여줍니다. 반대의 경우엔 이동한 만큼 늘려 줍니다. 변경할 수치는 계산만 해 놓습니다.

이제 오른쪽 손가락은 차이가 마이너스이면 늘려 줘야겠죠. 플러스면 왼쪽으로 이동한 것이니 줄여줍니다. 방식은 똑같죠. 역시 계산만 해 줍니다.

이제 x좌표에서는 width가 계산되었습니다. 핀치줌에서 레이아웃의 중심점을 유지한다면 새로운 width를 기반으로 기존 레이아웃의 중심점을 기반으로 레이아웃의 left를 다시 계산해 줍니다.

이렇게 y를 계산해서 최종적으로 계산된 left, top, width, height를 적용합니다.

Good luck 2 U~!
Will Kim (43,170 포인트) 님이 2018년 10월 19일 답변
...