Intereting Posts
Макет анимации макета материала Множественное исключение NotFoundException только на телефонах Huawei Как отобразить страницу контента Html с помощью веб-браузера в Android? Внедрение ListView в виджетах Android Android Authenticator запускает экран входа в систему, когда нет учетной записи Как я могу управлять устройством Android с ПК? Невозможно запустить активность – время уничтожения активности для истории LibGDX: Как можно легко определить, потерялся ли контекст opengl? Android O кастинг для findViewById больше не нужен? Может ли невидимый апостроф в литерале, определенном в strings.xml, вызвать мое приложение для сбоя? Как открыть приложение FB с помощью намерения и показать понравившуюся страницу в приложении FB? Parse Arabic XML в Android Проблемы с попыткой создания приложения Kotlin с Android Studio 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); } }