English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
서론
안드로이드 개발에서, 뷰는 항상 안드로이드 개발자들의 아픈 골칫거리였습니다. 한편으로는 진보를 원하고, 다른 한편으로는 진보를 두려워합니다. 안드로이드의 뷰는 진보의 길에서 가장 큰 장애물이며, 이는 많은 것을 포함하고 있기 때문입니다. 예를 들어, 이번에 쓰려는 뷰 이동뿐만 아니라, 뷰의 터치 이벤트 전달, 커스텀 뷰 생성 등이 매우 중요하며 피할 수 없는 어려운 문제들입니다. 하지만 어떤 경우에도, 지금克服하지 않는 어려움은 앞으로 어려움에 의해克服될 것입니다.
이전에, 우리는 Android 좌표계의 정의 규칙 및 View의 몇 가지 위치 매개변수를 먼저 이해해야 합니다.
Android 좌표계
View의 위치 및 크기는 left, top, right, bottom 네 가지 매개변수로 결정되며, 이 네 가지 매개변수는 모두 부모 View에 대한 상대적인 값입니다.
int width = right-left; int height = bottom-top;
Activity의 레이아웃이 완료된 후, View의 몇 가지 메서드를 통해 이러한 매개변수 정보를 얻을 수 있습니다:
//left, top, right, bottom 값을 얻기 int left = getLeft(); int top = getTop(); int right = getRight(); int bottom = getBottom();
또한 Android 3.0 이후에 x, y, translationX, translationY 등의 매개변수를 추가했습니다. (x, y)는 ViewGroup 내에서 View의 왼쪽 상단의 x, y 값을 나타냅니다. translationX, translationY는 View를 이동시키는 데 사용됩니다. 기본적으로 모두 0으로 설정되어 있습니다. View의 setTranslationX()을 호출하면/setTranslationY() 이후 변경됩니다.
//x, y, translationX, translationY 매개변수의 얻기 int x = getX(); int y = getY(); int translationX = getTranslationX(); int translationY = getTranslationY();
PS:View의 setTranslationX()와 setTranslationY() 메서드를 호출하면 View가 지정된 거리로 이동할 수 있지만, 이 과정은 즉시 완료됩니다. View의 이동이 더 부드럽게 느껴지도록 하기 위해, View의 애니메이션 속성을 사용하여 translationX와 translationY를 지정할 수 있습니다.
ObjectAnimator valueAnimator = ObjectAnimator.ofFloat(textView, "translationX", 200); valueAnimator.setDuration(2000); valueAnimator.start();
또한, View에 setTranslationX()와 setTranslationY()를 설정한 후, 설정된 값이 변경되지 않으면, 그림자는 한 번만 이동합니다. 즉, 최초로 지정된 이동 거리입니다. 소스 코드를 확인한 후에는 이유를 발견했습니다. 설정된 값이 현재 translationX와 translationY와 일치하지 않으면 이동합니다.
View의 일부 기본 파라미터를 이해한 후, View의 세 가지 이동 방식에 대해 살펴보겠습니다.
1. Android 시스템에서 제공하는 scrollTo() 사용/scrollBy() 메서드는 View를 이동시킵니다.
scrollTo()와 scrollBy()의 이동의 본질은 모두 View입니다./ViewGroup에 있는 내용입니다. 그리고 이동 과정은 순간적으로 완료됩니다. 따라서 더 나은 이동 효과를 위해 Scroller 클래스와 함께 사용해야 합니다. 또한, 위의 Translation과는 달리, 이는 View 자체를 이동시킵니다. 이 점을 잘 이해해야 합니다.
scrollTo()와 scrollBy()는 View의 메서드이며, Scroller의 메서드가 아닙니다. 그러나 View의 원활한 이동을 제어하는 데 Scroller 클래스와 밀접한 관련이 있습니다.
scrollTo() : 이동할绝对 위치를 의미하며, 위치가 변경되지 않으면 여러 번 호출해도 효과가 없습니다.
scrollTo 이동 과정 시각화
scrollBy() : 본질적으로 scrollTo()를 호출하는 것입니다. 현재 위치와 설정된 거리의 합을 더해 scrollTo()를 호출합니다. 따라서 여러 번 호출하면 매번 일정한 거리를 이동하게 되며, 이는 scrollTo()의 본질과의 차이입니다.
scrollBy 이동 과정 시각화
PS:위 두 장의 그림에 대해, 사실 저는 항상 상대적 절대적인 것에 대해 완전히 이해하지 못했기 때문에, 두 장의 손 그림이 더 쉽게 이해될 수 있을 것 같습니다. 또한 scrollTo()와 scrollBy()의 이동 방향 문제에 대해, 위에서 이미 Android의 좌표계를 그려놓았습니다. x축은 왼쪽에서 오른쪽으로가는 방향이 긍정적이고, y축은 위에서 아래로가는 방향이 긍정적입니다. 하지만 이는 scrollTo와 scrollBy에 적용되지 않으며, scrollTo와 scrollBy는 정 반대로, x축은 왼쪽에서 오른쪽으로가는 방향이 음성이고, y축은 위에서 아래로가는 방향이 음성입니다. 정말로 좀 비쌈입니다.
Scroller 클래스 분석: 왜 Scroller 클래스의 메서드를 사용하여 View를/ViewGroup의 내용을 어떻게 이동시키는지 분석해 보겠습니다.
먼저
Scroller 클래스의 객체 mScroller를 생성합니다.
그런 다음
View가 지정된 시간 내에 지정된 위치로 이동하려면 startScroll() 메서드를 호출합니다. startScroll()는 Scroller 클래스의 메서드이며, Scroller 클래스에는 또한 자주 사용되는 filing() 메서드가 있습니다. 이 메서드는 일반적으로 원활한 이동을 처리하고, 스르르 움직임 이후의 진동 효과를 만들어 View의 이동을 더 진정성 있게 만듭니다. 아래에서 startScroll()의 소스 코드를 보겠습니다.:
//네 개를 받습니다./다섯 개의 매개변수가 있습니다. duration을 설정하지 않으면 기본 값이 됩니다. 이 네 개의 매개변수는 이해하기 쉽기 때문에 설명하지 않겠습니다. public void startScroll(int startX, int startY, int dx, int dy, int duration) { ... }
보통 이 메서드를 호출한 후 View의 invalidate()를 호출합니다. 이 메서드는 View의 draw() 메서드를 트리거할 수 있습니다. draw()에서 computeScroll()를 호출하며, 소스 코드에서 computeScroll()는 빈 메서드입니다. 이것이 computeScroll() 메서드를 재정의해야 하는 이유입니다. 실제 이동 작업은 computeScroll()에서 수행됩니다.
@Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //View의 postInvalidate()를 호출해야 합니다./invalidate()를 추가하지 않으면 View의 이동은 첫 프레임에만 발생합니다. postInvalidate(); } super.computeScroll(); }
위에서 본 것처럼 Scroller 클래스에는 computeScrollOffset() 메서드가 더 있고, 이 메서드는 무엇을 합니까? 주요 기능은 mCurrX와 mCurrY가 변경되었는지 확인하고, 변경되면 true를 반환하고, 변경되지 않으면 false를 반환하는 것입니다. 이 메서드의 판단을 통해 scrollTo()를 지속적으로 호출하여 View를 이동시킬 필요가 있는지 결정할 수 있습니다. 여기서 예제를 하나 더 제공하겠습니다. scrollTo()를 사용하여 View를 손가락 움직임에 따라 이동시키기:
public class CuView extends LinearLayout { private float mStartX; private float mStartY; private Scroller mScroller; /** * 第一次滑动是否完成 */ private boolean isFirstFinish; public CuView(Context context) { super(context); init(context); } public CuView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { mScroller = new Scroller(context); } public CuView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CuView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context); } /** * View가 손가락에 따라 움직이도록 합니다 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: /** * 第一次移动完成后,我们不需要再去拿开始的位置了,否则造成View重新移动的最起始的位置。 */ if (!isFirstFinish) { mStartX = event.getRawX(); mStartY = event.getRawY(); } break; case MotionEvent.ACTION_MOVE: scrollTo((int) (mStartX - event.getRawX()), (int) (mStartY - event.getRawY()); break; case MotionEvent.ACTION_UP: //첫 번째 이동 완료 isFirstFinish = true; break; } return true; } /** * startScroll 테스트 */ public void startScroll() { /** * Scroller 이동 방향에 유의하십시오. */ 2 2 -500, -500, 5000); invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } super.computeScroll(); } }
2. 애니메이션을 사용하여 View를 이동시키기
여기에는 View의 Tween Animation도 포함됩니다./Frame Animation, 그리고3.0 이후 추가된 Property Animation. 이는 View의 이미지를 이동시키며, View 자체의 위치 및 크기는 변하지 않습니다.
3. View의 LayoutParams를 설정하여 View를 이동시키기
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams(); layoutParams.leftMargin = 50; textView.requestLayout();
요약
이제 Android View 이동의 요약입니다.3모든 방법의 내용을 포함하고 있으며, 이 글의 내용이 모두 여러분이 Android를 개발할 때 도움이 되기를 바랍니다. 의문이 있으면 댓글을 달고 교류하세요.