English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Обзор трех способов перемещения View в Android

Введение

В разработке Android, View всегда была камнем преткновения для разработчиков Android, с одной стороны, они хотят продвинуться, с другой стороны, они боятся продвинуться, можно сказать, что View в Android является самым большим камнем преткновения на пути к прогрессу, потому что он включает в себя слишком много вещей, например, то, что мы пишем в этой статье о перемещении View, включая передачу событий касания View, создание пользовательских View, все это极其重要 и необходимо решить. Но无论如何, те трудности, которые не будут преодолены сейчас, будут преодолены в будущем.

До этого我们先了解一下 Android-координатную систему и некоторые параметры положения View.

Координатная система Android

Положение и размер Views определяются четырьмя параметрами: 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) представляют собой значения x и y в координатах ViewGroup, в котором расположен View, а translationX, translationY используются для перемещения Views. По умолчанию они равны 0 и изменяются после вызова setTranslationX()/setTranslationY() вида.

// Получение параметров x, y, translationX, translationY
 int x = getX();
 int y = getY();
 int translationX = getTranslationX();
 int translationY = getTranslationY();

PS: Вызов методов setTranslationX() и setTranslationY() класса View позволяет перемещать вид на указанное расстояние, но этот процесс выполняется моментально. Чтобы сделать движение вида более плавным, можно использовать анимацию свойств вида для задания translationX и translationY.

ObjectAnimator valueAnimator = ObjectAnimator.ofFloat(textView, "translationX", 200);
 valueAnimator.setDuration(2000);
 valueAnimator.start();

Кроме того, если после установки setTranslationX() и setTranslationY() значения не изменились, то он будет перемещаться только один раз, то есть расстояние首次指定的 перемещения. После просмотра исходного кода мы обнаружили причину:原来 после установки значения его сравнивают с текущим translationX, translationY, и если они различаются, то они перемещаются.

После того как мы изучили некоторые основные параметры View, давайте рассмотрим три способа перемещения View.

1. Использование методов scrollTo()/scrollBy() системы Android для перемещения View.

Независимо от того, scrollTo() или scrollBy(), их суть перемещения заключается в содержимом View/ViewGroup, и их процесс перемещения завершается моментально. Поэтому, чтобы реализовать более hyväйный эффект перемещения, его необходимо использовать вместе с классом 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(), который является методом класса Scroller. В классе Scroller также есть метод fluent(), который также часто используется, он主要负责smooth movement, обычно создает эффект инерции после скролла, что делает движение View более реалистичным. Вот пример исходного кода метода startScroll():

//Он принимает четыре/пять параметров. Если duration не установлено, то используется значение по умолчанию. Эти четыре параметра несложно понять, поэтому здесь они не объясняются.
 public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
 ...
 }

Обычно после вызова этой функции мы вызываем invalidate() View, эта функция может инициировать метод draw() View. В draw() вызывается computeScroll(), в исходном коде мы видим, что computeScroll() - это пустой метод, именно поэтому нам нужно переопределить метод computeScroll(). Потому что真正的 движение выполняется в computeScroll().

@Override
 public void computeScroll() {
 if (mScroller.computeScrollOffset()) {
  scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
  //Обязательно нужно вызывать 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,
  */
 mScroller.startScroll(20, 20, -500, -500, 5000);
 invalidate();
 }
 @Override
 public void computeScroll() {
 if (mScroller.computeScrollOffset()) {
  scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
  invalidate();
 }
 super.computeScroll();
 }
}

Второй способ: использование анимации для перемещения View

Здесь включены анимации View (Tween Animation/Frame Animation) и Property Animation, добавленные после версии 3.0. Перемещается изображение View, а само View и его размеры не изменяются.

Третий способ: настройка LayoutParams View для перемещения View

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams();
 layoutParams.leftMargin = 50;
 textView.requestLayout();

Обобщение

Вот и все, что нужно знать о трёх способах перемещения View в Android. Надеюсь, что материал статьи поможет вам в разработке Android. Если у вас есть вопросы, вы можете оставить комментарий для обсуждения.

Рекомендуем