ObjectAnimator, Changing “ScaleX” or “Left,” but text doesn't stay properly centered

一笑奈何 提交于 2019-12-25 04:34:24

问题


I need to animate three elements to show additional info when the user clicks on a button. I have a label (TextView tvAvailableToPair) that slides out from under a button (Button bSearchForDevices)--both of which start with a width of fill_parent--while it simultaneously slides up. I have it changing perfectly, but it isn't animated: I've achieved that via SetLayoutParams:

bSearchForDevices.setText(R.string.bSearchForDevicesDiscoveryStartedText);
FrameLayout.LayoutParams lp_bSFD = 
        (FrameLayout.LayoutParams) bSearchForDevices.getLayoutParams();
int mWidthOfBSearchForDevices = lp_bSFD.width = 
        (int) Math.round(fMeasureScreenWidth * 0.4);
int mLeftMarginOfBSearchForDevices = lp_bSFD.leftMargin = 
        Math.round(fMeasureScreenWidth - (fHorizontalMargin + lp_bSFD.width));
bSearchForDevices.setLayoutParams(lp_bSFD);

lp_bSFD = (FrameLayout.LayoutParams) tvAvailableToPair.getLayoutParams();
lp_bSFD.width = mLeftMarginOfBSearchForDevices;
lp_bSFD.leftMargin = 0;
tvAvailableToPair.setLayoutParams(lp_bSFD);
ViewGroup.LayoutParams lp = llAvailableToPair.getLayoutParams();
lp.height = Math.round(getResources().getDimensionPixelSize(
        R.dimen.llAvailableToPair_height_expanded) * MainActivity.displayMetrics.density);

I learned a FrameLayout allows you to place elements on different Z-axis values (on top of or below another element; to cover or be covered over by another element). Here's my xml for this activity:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity"
    android:id="@+id/rlDeviceListLayout"
    android:background="@android:color/holo_blue_dark"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:fitsSystemWindows="true"
    android:animateLayoutChanges="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" >

    <android.support.design.widget.AppBarLayout
        android:id="@+id/ablToolbarLayout"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_alignParentTop="true"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            app:popupTheme="@style/AppTheme.PopupOverlay" />
    </android.support.design.widget.AppBarLayout>

    <LinearLayout>
        <!-- Existing devices for user to select -->
    </LinearLayout>

    <!-- This is what needs to be animated up once user presses the button -->
    <LinearLayout
        android:id="@+id/llAvailableToPairLayout"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="@dimen/llAvailableToPair_height_collapsed"
        android:layout_alignParentBottom="true"
        android:paddingTop="4dp">

        <!-- This Layout is used to stack the button over the textview -->
        <FrameLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:layout_marginBottom="4dp">

            <!-- We'll change the width of this programmatically so that it appears to 
                elegantly slide to the left -->
            <TextView
                android:id="@+id/tvAvailableToPair"
                android:text="@string/tvAvailableToPair"
                android:layout_width="fill_parent"
                android:layout_height="@dimen/bSearchForDevices_height"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:inputType="none"
                android:gravity="center"
                android:foregroundGravity="left"
                android:textSize="16sp"
                android:textColor="#ffffff" />

            <!-- We'll change the text, width and left of this so that it reveals the 
                textview under it. It needs to appear as if it were elegantly squeezed 
                toward the right -->
            <Button
                android:id="@+id/bSearchForDevices"
                android:text="@string/bSearchForDevicesPreliminaryText"
                android:layout_width="fill_parent"
                android:layout_height="@dimen/bSearchForDevices_height"
                android:layout_marginLeft="@dimen/activity_horizontal_margin"
                android:layout_marginRight="@dimen/activity_horizontal_margin"
                android:foregroundGravity="right"
                android:visibility="visible"
                android:theme="@style/Base.ThemeOverlay.AppCompat.Dark"
                android:gravity="center" />
        </FrameLayout>

        <ListView
            android:id="@+id/lvAvailableToPair"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:visibility="visible" />
    </LinearLayout>
</RelativeLayout>

Its the last three elements I'm changing. Using SetLayoutParams keeps the text centered (and I shorten the text on the button to allow for smaller screens and the label -- I'll need to animate that as well next, possibly using TextSwitcher Animate Text Using TextSwitcher In Android) after the change. Moving on to getting those changes to animate, I had to use a different approach:

bSearchForDevices.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            FrameLayout.LayoutParams lpTVATP = (FrameLayout.LayoutParams) tvAvailableToPair.getLayoutParams();
            Paint paint = new Paint();
            AnimatorSet RevealAvailableDevices = new AnimatorSet();
            float fMeasuretvAvailableToPairTextWidth = paint.measureText(tvAvailableToPair.getText().toString());       // Function returns dp, not pixels
            float fMeasurebSearchForDevicesTextWidth = paint.measureText(bSearchForDevices.getText().toString());
            float fMeasureScreenWidth = MainActivity.displayMetrics.widthPixels;    // + 0.5f;         // Extra 0.5 to simplify/speed up rounding w/o a lot of excess code (LoungeKatt, via https://stackoverflow.com/questions/1016896/get-screen-dimensions-in-pixels) and used on Google's Android docs for just this purpose @ https://developer.android.com/guide/practices/screens_support.html#dips-pels
            float fHorizontalMargin;
            // If the screen is cramped, we'll shorten the margins:
            if (fMeasuretvAvailableToPairTextWidth > (fMeasureScreenWidth * 0.5)) {
                fHorizontalMargin = (getResources().getDimension(R.dimen.activity_horizontal_margin_compressed) / MainActivity.displayMetrics.density);
            } else {
                fHorizontalMargin = (getResources().getDimension(R.dimen.activity_horizontal_margin) / MainActivity.displayMetrics.density);
            }

            /* This works PERFECTLY, but isn't animated:
            bSearchForDevices.setText(R.string.bSearchForDevicesDiscoveryStartedText);
            FrameLayout.LayoutParams lp_bSFD = (FrameLayout.LayoutParams) bSearchForDevices.getLayoutParams();
            int mWidthOfBSearchForDevices = lp_bSFD.width = (int) Math.round(fMeasureScreenWidth * 0.4);
            int mLeftMarginOfBSearchForDevices = lp_bSFD.leftMargin = Math.round(fMeasureScreenWidth - (fHorizontalMargin + lp_bSFD.width));
            bSearchForDevices.setLayoutParams(lp_bSFD);

            lp_bSFD = (FrameLayout.LayoutParams) tvAvailableToPair.getLayoutParams();
            lp_bSFD.width = mLeftMarginOfBSearchForDevices;
            lp_bSFD.leftMargin = 0;
            tvAvailableToPair.setLayoutParams(lp_bSFD);
            ViewGroup.LayoutParams lp = llAvailableToPair.getLayoutParams();
            lp.height = Math.round(getResources().getDimensionPixelSize(R.dimen.llAvailableToPair_height_expanded) * MainActivity.displayMetrics.density);
            */
            float fWidthOfbSearchForDevices = (float) ((fMeasureScreenWidth * 0.4));
            float fWidthOftvATP = (fMeasureScreenWidth - ((fWidthOfbSearchForDevices * 1) + (fHorizontalMargin * 2)));
            float fXOfbSearchForDevices = (fMeasureScreenWidth - (fWidthOfbSearchForDevices + (1 * fHorizontalMargin)));
            Log.d(TAG, "...\nfMeasureScreenWidth = " + fMeasureScreenWidth + "\nfWidthOfbSearchForDevices = " + fWidthOfbSearchForDevices + "\nfHorizontalMargin = " + fHorizontalMargin +
                    "\nbSearchForDevices.getX() = " + bSearchForDevices.getX() + "\n  (fXOfbSearchForDevices) X is going to be " + fXOfbSearchForDevices);

            ObjectAnimator aniButtonMove = ObjectAnimator.ofInt(bSearchForDevices, "Left", (int) fXOfbSearchForDevices);
            bSearchForDevices.setPivotX(fXOfbSearchForDevices + (fWidthOfbSearchForDevices / 2));   // No effect: To be in the center of where the button will end up at.
            ObjectAnimator aniTextViewResize = ObjectAnimator.ofInt(tvAvailableToPair, "Right", (int) fXOfbSearchForDevices);
            Log.d(TAG, "tvAvailableToPair's width = " + tvAvailableToPair.getWidth() + "     tvAvailableToPair is supposed to be " + fWidthOftvATP + "\nWidth of bSearchForDevices = " + bSearchForDevices.getWidth());
            RevealAvailableDevices.play(aniTextViewResize).with(aniButtonMove);
            RevealAvailableDevices.start();

This produces an animation that correctly moves the bounds of the textview and button, but doesn't center the text to the new bounds (edges/left and right coordinates) of those elements: my button now shows a lot of leading empty space just before it shows S, E and half of A of "Search For Devices;" in other words, it's clipped. I need it kept centered (as is when using SetLayoutParams). The same applies to the textview: the last 5 letters of "Available Devices" get clipped off.

Is there a better way to create this animation that has three elements changing shape (and preferably changing the button's text as well)? I've tried ScaleX but am unable to get it to sync correctly as it pivots at the center without sliding to the right side, nor the textview to slide while it shrinks...maybe ScaleX but change the pivot to the left edge... Or maybe a PropertyValuesHolder?

3/15/2016 Update: Here's what I've got: https://www.dropbox.com/s/n14hed6xcknfh9b/SS_20160315_135938.mp4?dl=0

And what I need it to look like post animation

来源:https://stackoverflow.com/questions/35936379/objectanimator-changing-scalex-or-left-but-text-doesnt-stay-properly-cent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!