Intereting Posts
LocationClient не дает обратного вызова, когда свет экрана гаснет, но мой WakefulThread работает безупречно, как ожидалось Android позволяет загружать несколько файлов (максимум 150 МБ) на PHP Server Как использовать событие EditText onTextChanged, когда я нажимаю номер? Изменение ориентации экрана во время обезьяны Midi Library for Android Должен ли я использовать Фрагменты для получения LoaderManager? Отправить команду на Bluetooth с Android-устройства Android-приложение, использующее android.permission.READ_LOGS – это невежливо? ANR при случайном использовании приложения Почему я получаю исключение InstantiationException, если пытаюсь запустить службу? RecyclerView отключает видимый вид Как разместить пункты меню в режиме навигации? LayoutInflater иногда (случайно) раздувается с неправильным цветом фона Отключение центра MapFragment для анимации, перемещающей как целевой лат / lng, так и уровень масштабирования Синхронизированное воспроизведение звука на отдельных устройствах Android

Android – анимация масштабирования с использованием AnimatorSet

В официальном учебном курсе «Масштабирование» используется AnimatorSet для увеличения масштаба. Это создает иллюзию нисходящего движения по мере расширения взгляда. Позже AnimatorSet просто переигрывается назад, чтобы создать иллюзию уменьшения.

Масштабирование с нисходящим движением То, что мне нужно реализовать, – это точное обратное. Мне нужно начать с расширенного вида и сжать его в меньший вид с восходящим движением:

Масштабирование с восходящим движением Кажется, я не могу использовать код разворота в примере. Этот пример предполагает, что вы сначала увеличиваете масштаб изображения и расширяете его, а затем сжимаете его обратно в значок эскиза.

Вот что я пробовал до сих пор. Мой XML-макет

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#1999da"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:orientation="horizontal" android:layout_gravity="center" android:gravity="center"> <!-- The final shrunk image --> <ImageView android:id="@+id/thumb_button_1" android:layout_width="wrap_content" android:layout_height="50dp" android:layout_marginRight="1dp" android:visibility="invisible"/> </LinearLayout> </LinearLayout> <!-- The initial expanded image that needs to be shrunk --> <ImageView android:id="@+id/expanded_image" android:layout_width="wrap_content" android:layout_height="125dp" android:layout_gravity="center" android:src="@drawable/title_logo_expanded" android:scaleType="centerCrop"/> </FrameLayout> 1 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#1999da"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:orientation="horizontal" android:layout_gravity="center" android:gravity="center"> <!-- The final shrunk image --> <ImageView android:id="@+id/thumb_button_1" android:layout_width="wrap_content" android:layout_height="50dp" android:layout_marginRight="1dp" android:visibility="invisible"/> </LinearLayout> </LinearLayout> <!-- The initial expanded image that needs to be shrunk --> <ImageView android:id="@+id/expanded_image" android:layout_width="wrap_content" android:layout_height="125dp" android:layout_gravity="center" android:src="@drawable/title_logo_expanded" android:scaleType="centerCrop"/> </FrameLayout> 

И вот метод, который выполняет операцию уменьшения. Я в основном попытался изменить процедуру в учебнике:

 private void zoomImageFromThumbReverse(final View expandedImageView, int imageResId, final int duration) { // If there's an animation in progress, cancel it immediately and proceed with this one. if (mCurrentAnimator != null) { mCurrentAnimator.cancel(); } // Load the low-resolution "zoomed-out" image. final ImageView thumbView = (ImageView) findViewById(R.id.thumb_button_1); thumbView.setImageResource(imageResId); // Calculate the starting and ending bounds for the zoomed-in image. This step // involves lots of math. Yay, math. final Rect startBounds = new Rect(); final Rect finalBounds = new Rect(); final Point globalOffset = new Point(); // The start bounds are the global visible rectangle of the container view (ie the FrameLayout), and the // final bounds are the global visible rectangle of the thumbnail. Also // set the container view's offset as the origin for the bounds, since that's // the origin for the positioning animation properties (X, Y). findViewById(R.id.container).getGlobalVisibleRect(startBounds, globalOffset); thumbView.getGlobalVisibleRect(finalBounds); startBounds.offset(-globalOffset.x, -globalOffset.y); finalBounds.offset(-globalOffset.x, -globalOffset.y); // Adjust the start bounds to be the same aspect ratio as the final bounds using the // "center crop" technique. This prevents undesirable stretching during the animation. // Also calculate the start scaling factor (the end scaling factor is always 1.0). float startScale; if ((float) finalBounds.width() / finalBounds.height() > (float) startBounds.width() / startBounds.height()) { // Extend start bounds horizontally startScale = (float) startBounds.height() / finalBounds.height(); float startWidth = startScale * finalBounds.width(); float deltaWidth = (startWidth - startBounds.width()) / 2; startBounds.left -= deltaWidth; startBounds.right += deltaWidth; } else { // Extend start bounds vertically startScale = (float) startBounds.width() / finalBounds.width(); float startHeight = startScale * finalBounds.height(); float deltaHeight = (startHeight - startBounds.height()) / 2; startBounds.top -= deltaHeight; startBounds.bottom += deltaHeight; } // Hide the expanded-image and show the zoomed-out, thumbnail view. When the animation begins, // it will position the zoomed-in view in the place of the thumbnail. expandedImageView.setAlpha(0f); thumbView.setVisibility(View.VISIBLE); // Set the pivot point for SCALE_X and SCALE_Y transformations to the top-left corner of // the zoomed-in view (the default is the center of the view). thumbView.setPivotX(0f); thumbView.setPivotY(0f); // Construct and run the parallel animation of the four translation and scale properties // (X, Y, SCALE_X, and SCALE_Y). AnimatorSet set = new AnimatorSet(); set .play(ObjectAnimator.ofFloat(thumbView, View.X, startBounds.left, finalBounds.left)) .with(ObjectAnimator.ofFloat(thumbView, View.Y, startBounds.top, finalBounds.top)) .with(ObjectAnimator.ofFloat(thumbView, View.SCALE_X, startScale, 1f)) .with(ObjectAnimator.ofFloat(thumbView, View.SCALE_Y, startScale, 1f)); //set.setDuration(mShortAnimationDuration); set.setDuration(duration); set.setInterpolator(new DecelerateInterpolator()); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mCurrentAnimator = null; } @Override public void onAnimationCancel(Animator animation) { mCurrentAnimator = null; } }); set.start(); mCurrentAnimator = set; // Upon clicking the zoomed-out image, it should zoom back down to the original bounds // and show the thumbnail instead of the expanded image. final float startScaleFinal = startScale; thumbView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mCurrentAnimator != null) { mCurrentAnimator.cancel(); } // Animate the four positioning/sizing properties in parallel, back to their // original values. AnimatorSet set = new AnimatorSet(); set .play(ObjectAnimator.ofFloat(thumbView, View.X, startBounds.left)) .with(ObjectAnimator.ofFloat(thumbView, View.Y, startBounds.top)) .with(ObjectAnimator .ofFloat(thumbView, View.SCALE_X, startScaleFinal)) .with(ObjectAnimator .ofFloat(thumbView, View.SCALE_Y, startScaleFinal)); //set.setDuration(mShortAnimationDuration); set.setDuration(duration); set.setInterpolator(new DecelerateInterpolator()); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { expandedImageView.setAlpha(1f); thumbView.setVisibility(View.GONE); mCurrentAnimator = null; } @Override public void onAnimationCancel(Animator animation) { expandedImageView.setAlpha(1f); thumbView.setVisibility(View.GONE); mCurrentAnimator = null; } }); set.start(); mCurrentAnimator = set; } }); } 

Я onCreate() этот метод в onCreate() следующим образом:

 final View expandedImageView = findViewById(R.id.expanded_image); new Handler().postDelayed(new Runnable(){ public void run() { zoomImageFromThumbReverse(expandedImageView, R.drawable.title_logo_min, 1000); }}, 1000); 

Ну, вот и все, ребята. Он не работает. Я не понимаю, почему. Демо-пример отлично работает, так почему же это не работает? Возьми гусака и скажи мне, сошел ли я с ума.

Может ли кто-нибудь опознать ошибку? Или указать мне в правильном направлении? Вся помощь будет принята с благодарностью.

Solutions Collecting From Web of "Android – анимация масштабирования с использованием AnimatorSet"

Это решение, которое я использовал в конечном итоге:

 private void applyAnimation(final View startView, final View finishView, long duration) { float scalingFactor = ((float)finishView.getHeight())/((float)startView.getHeight()); ScaleAnimation scaleAnimation = new ScaleAnimation(1f, scalingFactor, 1f, scalingFactor, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(duration); scaleAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); Display display = getWindowManager().getDefaultDisplay(); int H; if(Build.VERSION.SDK_INT >= 13){ Point size = new Point(); display.getSize(size); H = size.y; } else{ H = display.getHeight(); } float h = ((float)finishView.getHeight()); float verticalDisplacement = (-(H/2)+(3*h/4)); TranslateAnimation translateAnimation = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0, Animation.ABSOLUTE, verticalDisplacement); translateAnimation.setDuration(duration); translateAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); AnimationSet animationSet = new AnimationSet(false); animationSet.addAnimation(scaleAnimation); animationSet.addAnimation(translateAnimation); animationSet.setFillAfter(false); startView.startAnimation(animationSet); } 

Ключевым фактором здесь является значение toYDelta в параметре TranslateAnimation :

 toYDelta = (-(H/2)+(3*h/4)); 

Понимание того, почему это работает, – это главное. Остальное в основном простое.

Хорошо, я думаю, вы хотите уменьшить масштаб с восходящим движением от ваших изображений и описания. Я не могу понять ваш код, кажется мне слишком сложным (я нооб). Теперь я сделал то, что вам нужно, используя следующий код. Сначала я объявляю относительный макет с изображением, этот относительный макет будет контейнером. Я установил начальную ширину ширины, но мы изменим ее позже из кода.

 <RelativeLayout android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ImageView android:id="@+id/imageView" android:layout_width="400dp" android:layout_height="200dp" android:layout_centerHorizontal="true" android:scaleType="fitXY" android:src="@drawable/my_image"/> </RelativeLayout> 

Теперь в действии я устанавливаю слушателя для изменения макета, чтобы получить реальный размер контейнера. Затем установите макет для ImageView.

 public class MainActivity extends Activity { ImageView im; RelativeLayout container; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Logger.init().hideThreadInfo().setMethodCount(0); setContentView(R.layout.activity_main); im = (ImageView) findViewById(R.id.imageView); container = (RelativeLayout) findViewById(R.id.container); container.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { setInitialPos(); container.getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); } int width; int height; int topMargin; private void setInitialPos() { Logger.e("container: " + container.getWidth() + " x " + container.getHeight()); width = container.getWidth(); height = 400; RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) im.getLayoutParams(); layoutParams.width = width; layoutParams.height = height; topMargin = (container.getHeight() - height) / 2; layoutParams.topMargin = topMargin; im.setLayoutParams(layoutParams); startAnimation(); } 

Мы должны анимировать три вещи здесь: ширина, высота и topMargin (для позиционирования). Итак, я объявляю три переменные для начальной позиции аниматора, и я вычисляю их при первоначальном размещении. Теперь нам нужно анимировать эти три переменные одновременно, что легко.

  private void startAnimation() { AnimatorSet animator = new AnimatorSet(); Animator widthAnimator = ObjectAnimator.ofInt(this, "width", width, 200); widthAnimator.setInterpolator(new LinearInterpolator()); Animator heightAnimator = ObjectAnimator.ofInt(this, "height", height, 100); heightAnimator.setInterpolator(new LinearInterpolator()); Animator marginAnimator = ObjectAnimator.ofInt(this, "topMargin", topMargin, 0); marginAnimator.setInterpolator(new LinearInterpolator()); animator.playTogether(widthAnimator, heightAnimator, marginAnimator); animator.setDuration(3000); animator.start(); } public void setWidth(int w) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) im.getLayoutParams(); layoutParams.width = w; im.setLayoutParams(layoutParams); } public void setHeight(int h) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) im.getLayoutParams(); layoutParams.height = h; im.setLayoutParams(layoutParams); } public void setTopMargin(int m) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) im.getLayoutParams(); layoutParams.topMargin = m; im.setLayoutParams(layoutParams); } }