与getGlobalVisibleRect混淆,不同的值

时间:2013-12-03 10:52:27

标签: android android-animation android-view objectanimator

我尝试使用Android开发者网站上的以下示例缩放FrameLayout:http://developer.android.com/training/animation/zoom.html

我的具体问题,在第一次动画是正确的时候,从thumbView扩展,第二次动画来自'某处'(中间/顶部到中心)。

我差不多,不同的是,我有一个Framelayout而不是ImageView,我提取函数以最小化View在一个额外的方法。现在看起来像这样:

private void zoomImageFromThumb(final View thumbView) {

    if (mCurrentAnimator != null) {
        mCurrentAnimator.cancel();
    }

    // here i building my custome layout

    startBounds = new Rect();
    final Rect finalBounds = new Rect();
    final Point globalOffset = new Point();

    thumbView.getGlobalVisibleRect(startBounds);
    findViewById(R.id.container)
            .getGlobalVisibleRect(finalBounds, globalOffset);
    startBounds.offset(-globalOffset.x, -globalOffset.y);
    finalBounds.offset(-globalOffset.x + 15, -globalOffset.y + 60);

    float startScale;
    if ((float) finalBounds.width() / finalBounds.height()
            > (float) startBounds.width() / startBounds.height()) {

        startScale = (float) startBounds.height() / finalBounds.height();
        float startWidth = startScale * finalBounds.width();
        float deltaWidth = (startWidth - startBounds.width()) / 2;
        startBounds.left -= deltaWidth;
        startBounds.right += deltaWidth;
    } else {

        startScale = (float) startBounds.width() / finalBounds.width();
        float startHeight = startScale * finalBounds.height();
        float deltaHeight = (startHeight - startBounds.height()) / 2;
        startBounds.top -= deltaHeight;
        startBounds.bottom += deltaHeight;
    }

    thumbView.setAlpha(0f);
    expandedImageView.setVisibility(View.VISIBLE);

    expandedImageView.setPivotX(0f);
    expandedImageView.setPivotY(0f);

    AnimatorSet set = new AnimatorSet();
    set
            .play(ObjectAnimator.ofFloat(expandedImageView, View.X,
                    startBounds.left, finalBounds.left))
            .with(ObjectAnimator.ofFloat(expandedImageView, View.Y,
                    startBounds.top, finalBounds.top))
            .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X,
            startScale, 1f)).with(ObjectAnimator.ofFloat(expandedImageView,
                    View.SCALE_Y, startScale, 1f));
    set.setDuration(mShortAnimationDuration);
    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;
}

startBounds变量是全局的,因为我需要知道最小化过程的位置。这里的最小化方法:

    private void minimizeViewFromThumb(final View thumbView) {
    if (mCurrentAnimator != null) {
                    mCurrentAnimator.cancel();
                }

                AnimatorSet set = new AnimatorSet();
                set.play(ObjectAnimator
                            .ofFloat(expandedImageView, View.X, startBounds.left))
                            .with(ObjectAnimator
                                    .ofFloat(expandedImageView, 
                                            View.Y,startBounds.top))
                            .with(ObjectAnimator
                                    .ofFloat(expandedImageView, 
                                            View.SCALE_X, startScaleFinal))
                            .with(ObjectAnimator
                                    .ofFloat(expandedImageView, 
                                            View.SCALE_Y, startScaleFinal));
                set.setDuration(mShortAnimationDuration);
                set.setInterpolator(new DecelerateInterpolator());
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {


                thumbView.setAlpha(1f);
                    expandedImageView.setVisibility(View.GONE);
                    mCurrentAnimator = null;
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                    thumbView.setAlpha(1f);
                    expandedImageView.setVisibility(View.GONE);
                    mCurrentAnimator = null;
                }
            });
            set.start();
            mCurrentAnimator = set;
}

如果我调试整个过程,我可以看到方法zoomViewFromThumb中的方法getGlobalVisibleRect给了我另一个值。

如果我调试行

finalBounds.offset(-globalOffset.x, -globalOffset.y);

这两个参数第一次是0和-60,第二次是最小化并重新创建后有15和360。

我不知道为什么会这样。

我尝试设置View.X和View.Y参数附加来自给定的thumbView,我尝试使用ObjectAnimator中的View.X,View.Y参数的常量值,但没有解决我的问题。

现在请帮帮我。

Greets Manu

1。编辑:失败是在Android版本4.1.2上我已经在Android 4.0的模拟器中测试它并且在那里工作正常

2。编辑:以下是xml文件,第一个是表示我的主Activity的xml文件(带动画),第二个表示我在主xml的FrameLayout中推送的TableLayout。 (请注意,目前我正在工作,我无法访问原文,现在这些xml文件很好,我记得很清楚)

第一个

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/relZoom"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/frameZoomOne"
        android:layout_width="160dp"
        android:layout_height="215dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="10dp" >
    </FrameLayout>

    <FrameLayout
        android:id="@+id/frameZoomTwo"
        android:layout_width="160dp"
        android:layout_height="215dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp" >
    </FrameLayout>

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="300dp"
        android:layout_height="408dp"
        android:visibility="invisible" >
    </FrameLayout>

    <FrameLayout
        android:id="@+id/containerTwo"
        android:layout_width="300dp"
        android:layout_height="408dp"
        android:visibility="invisible" >
    </FrameLayout>

</RelativeLayout>

第二个

    <?xml version="1.0" encoding="utf-8"?>
    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/tableLayout1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
        <TableRow
        android:id="@+id/tableRow1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <TextView
            android:id="@+id/textView1"
            android:text="Column 1"
            android:textAppearance="?android:attr/textAppearanceLarge" />

         <TextView
            android:id="@+id/textView2"
            android:text="Column 2"
            android:textAppearance="?android:attr/textAppearanceLarge" />
    </TableRow>
    <TableRow
        android:id="@+id/tableRow2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <ImageView
            android:id="@+id/imgView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/android" />
    </TableRow>
    <TableRow
        android:id="@+id/tableRow3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <TextView
            android:id="@+id/textView3"
            android:text="Column 3"
            android:textAppearance="?android:attr/textAppearanceLarge" />

         <TextView
            android:id="@+id/textView4"
            android:text="Column 4"
            android:textAppearance="?android:attr/textAppearanceLarge" />
    </TableRow>
</TableLayout>

第3。编辑:更正xml文件,然后添加活动:

public class SinglePlayerSp extends Activity implements OnClickListener
{
    private final Context mContext = this;
    private boolean mBackZoomOne = false;
    private FrameLayout frameZoomOne;
    private FrameLayout frameZoomTwo;
    private static Animator mCurrentAnimatorOne;
    private int mShortAnimationDuration;
    private float startScaleOne;
    private static Animator mCurrentAnimatorTwo;
    private float startScaleTwo;
    private Rect startBoundsOne;
    private Rect startBoundsTwo;
    private static View lastViewOne;
    private static View lastViewTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zoom);

        frameZoomOne = (FrameLayout) findViewById(R.id.frameZoomOne);
        frameZoomTwo = (FrameLayout) findViewById(R.id.frameZoomTwo);
        frameZoomOne.setOnClickListener(this);
        frameZoomTwo.setOnClickListener(this);

        mShortAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);

        cardItems = getIntent().getParcelableArrayListExtra(CARD_ITEMS);

        java.util.Collections.shuffle(cardItems);

    }

private void flipCard(boolean playerOneDeck, final int selectionFromPlayer, final boolean result)
    {
        Card cardItemOne = null;

            if (oneCards.get(0) != null)
            {
                cardItemOne = oneCards.get(0);
            }

            if (!mBackZoomOne)
            {
                getFragmentManager().beginTransaction().setCustomAnimations(R.animator.card_flip_right_in,
                        R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out).replace(
                        R.id.frameZoomOne, new CardBackFragment()).commit();
                mBackZoomOne = true;
            }
            else
            {
                getFragmentManager().beginTransaction().setCustomAnimations(R.animator.card_flip_right_in,
                        R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out).replace(
                        R.id.frameZoomOne,
                        CardFrontFragment.newInstance(cardItemPlayerOne, selectionFromPlayer, playerOneDeck)).commit();
                mBackZoomOne = false;

                zoomViewOneFromThumb(frameZoomOne, cardItemOne);
            }
    }

private void zoomViewOneFromThumb(final View thumbView, final Card cardItem)
    {
        if (mCurrentAnimatorOne != null)
        {
            mCurrentAnimatorOne.cancel();
        }

        lastViewOne = thumbView;
        View.getDefaultSize(0, 0);
        final FrameLayout expandFrameLayout = (FrameLayout) findViewById(R.id.container);

        LayoutInflater inflater =
                (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.fragment_card_front_clickable, null);

        TableRow rowOne = (TableRow) layout.findViewById(R.id.tableRow1);
        rowOne.setOnClickListener(this);

        TextView cardone = (TextView) layout.findViewById(R.id.textView1);
        TextView cardtwo = (TextView) layout.findViewById(R.id.textView2);
        TextView cardthree = (TextView) layout.findViewById(R.id.textView3);
        TextView cardfour = (TextView) layout.findViewById(R.id.textView4);

        Locale locale = getApplicationContext().getResources().getConfiguration().locale;

        cardone.setText(cardItem.TextOne());
        cardtwo.setText(cardItem.getTextTwo());
        cardthree.setText(cardItem.getTextThree());
        cardfour.setText(cardItem.TextFour());

        expandFrameLayout.addView(layout);

        startBoundsOne = new Rect();
        final Rect finalBounds = new Rect();
        final Point globalOffset = new Point();

        thumbView.getGlobalVisibleRect(startBoundsOne);
        findViewById(R.id.containerSp).getGlobalVisibleRect(finalBounds, globalOffset);
        startBoundsOne.offset(-globalOffset.x, -globalOffset.y);
        finalBounds.offset(-globalOffset.x + 15, -globalOffset.y + 50);

        if ((float) finalBounds.width() / finalBounds.height() > (float) startBoundsOne.width()
                / startBoundsOne.height())
        {
            startScaleOne = (float) startBoundsOne.height() / finalBounds.height();
            float startWidth = startScaleOne * finalBounds.width();
            float deltaWidth = (startWidth - startBoundsOne.width()) / 2;
            startBoundsOne.left -= deltaWidth;
            startBoundsOne.right += deltaWidth;
        }
        else
        {
            startScaleOne = (float) startBoundsOne.width() / finalBounds.width();
            float startHeight = startScaleOne * finalBounds.height();
            float deltaHeight = (startHeight - startBoundsOne.height()) / 2;
            startBoundsOne.top -= deltaHeight;
            startBoundsOne.bottom += deltaHeight;
        }

        thumbView.setAlpha(0f);
        expandFrameLayout.setVisibility(View.VISIBLE);

        expandFrameLayout.setPivotX(0f);
        expandFrameLayout.setPivotY(0f);

        AnimatorSet set = new AnimatorSet();
        set.play(ObjectAnimator.ofFloat(expandFrameLayout, View.X, startBoundsOne.left, finalBounds.left)).with(
                ObjectAnimator.ofFloat(expandFrameLayout, View.Y, startBoundsOne.top, finalBounds.top)).with(
                ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_X, startScaleOne, 1f)).with(
                ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_Y, startScaleOne, 1f));
        set.setDuration(mShortAnimationDuration);
        set.setInterpolator(new DecelerateInterpolator());
        set.addListener(new AnimatorListenerAdapter()
        {
            @Override
            public void onAnimationEnd(Animator animation)
            {
                mCurrentAnimatorOne = null;
            }

            @Override
            public void onAnimationCancel(Animator animation)
            {
                mCurrentAnimatorOne = null;
            }
        });
        set.start();
        mCurrentAnimatorOne = set;
        startScaleFinal = startScaleOne; // with this or without this, i have the same problem
    }

private void minimizeViewOne(final View expandFrameLayout)
    {
        AnimatorSet set = new AnimatorSet();
        set.play(ObjectAnimator.ofFloat(expandFrameLayout, View.X, startBoundsOne.left)).with(
                ObjectAnimator.ofFloat(expandFrameLayout, View.Y, startBoundsOne.top)).with(
                ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_X, startScaleFinal)).with(
                ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_Y, startScaleFinal));
        set.setDuration(mShortAnimationDuration);
        set.setInterpolator(new DecelerateInterpolator());
        set.addListener(new AnimatorListenerAdapter()
        {
            @Override
            public void onAnimationEnd(Animator animation)
            {
                lastViewOne.setAlpha(1f);
                expandFrameLayout.setVisibility(View.GONE);
                mCurrentAnimatorOne = null;
            }

            @Override
            public void onAnimationCancel(Animator animation)
            {
                lastViewOne.setAlpha(1f);
                expandFrameLayout.setVisibility(View.GONE);
                mCurrentAnimatorOne = null;
            }
        });
        set.start();
        mCurrentAnimatorOne = set;
    }
}

好的,现在是完整的代码。最后是一个onClick方法,在那里我收到用户操作。从那里我调用minimizeView方法,然后进行一些检查,之后我调用flipCard。就是这样。

2 个答案:

答案 0 :(得分:4)

根据谷歌开发者:

getGlobalVisibleRect(Rect r,Point globalOffset);

如果此视图的某些部分未被其父视图剪切,则以全局(根)坐标返回r中的该区域。

例如:   thumbView.getGlobalVisibleRect(startBounds);

这里假设thumbview的宽度为100,高度为75,并且分别从左和前16和51前进,这个方法在startBound(Rect)中存储值为left 16,top 51,right 16 + 100 = 116,bottom 51+ 75 = 126.即(16,51,116,126)

答案 1 :(得分:0)

我不知道你在哪里分配事件来关闭视图。但我会说导致错误的那一点,就是你读取一些变量,例如startScaleFinal = startScale;,必须在放大动画开始之前完成>并推广其他变量。

生病了我的完整工作示例,其中包含不同的功能和框架视图: 它工作得很好。

活性:

/*
 * Copyright 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.animationsdemo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;

/**
 * A sample showing how to zoom an image thumbnail to full-screen, by animating the bounds of the
 * zoomed image from the thumbnail bounds to the screen bounds.
 *
 * <p>In this sample, the user can touch one of two images. Touching an image zooms it in, covering
 * the entire activity content area. Touching the zoomed-in image hides it.</p>
 */
public class ZoomActivity extends FragmentActivity {
    /**
     * Hold a reference to the current animator, so that it can be canceled mid-way.
     */
    private Animator mCurrentAnimator;

    /**
     * The system "short" animation time duration, in milliseconds. This duration is ideal for
     * subtle animations or animations that occur very frequently.
     */
    private int mShortAnimationDuration;
    final Rect finalBounds = new Rect();
    final Point globalOffset = new Point();
    final Rect startBounds = new Rect();
    float startScale;
    FrameLayout expandedImageView;

    float startScaleFinal  ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zoom);

        // Hook up clicks on the thumbnail views.

        final View thumb1View = findViewById(R.id.thumb_button_1);
        thumb1View.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                zoomImageFromThumb(thumb1View, R.drawable.image1);
            }
        });

        final View thumb2View = findViewById(R.id.thumb_button_2);
        thumb2View.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                zoomImageFromThumb(thumb2View, R.drawable.image2);
            }
        });

        // Retrieve and cache the system's default "short" animation time.
        mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
    }


    private void zoomImageFromThumb(final View thumbView, int imageResId) {
        // If there's an animation in progress, cancel it immediately and proceed with this one.
        if (mCurrentAnimator != null) {
            mCurrentAnimator.cancel();
        }

        // Load the high-resolution "zoomed-in" image.
     expandedImageView = (FrameLayout) findViewById(R.id.expanded_image);


        // The start bounds are the global visible rectangle of the thumbnail, and the
        // final bounds are the global visible rectangle of the container view. 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).
        thumbView.getGlobalVisibleRect(startBounds);
        findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);
        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).

        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 thumbnail and show the zoomed-in view. When the animation begins,
        // it will position the zoomed-in view in the place of the thumbnail.
        thumbView.setAlpha(0f);
        expandedImageView.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).
        expandedImageView.setPivotX(0f);
        expandedImageView.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(expandedImageView, View.X, startBounds.left,
                        finalBounds.left))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top,
                        finalBounds.top))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
        set.setDuration(mShortAnimationDuration);
        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-in image, it should zoom back down to the original bounds
        // and show the thumbnail instead of the expanded image.
        startScaleFinal = startScale;
   expandedImageView.setOnClickListener(new View.OnClickListener() {


            @Override
            public void onClick(View view) {
                minimizeViewFromThumb(thumbView);
              }
        });
    }
    private void minimizeViewFromThumb(final View thumbView) {  

        // Upon clicking the zoomed-in image, it should zoom back down to the original bounds
        // and show the thumbnail instead of the expanded image.


                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(expandedImageView, View.X, startBounds.left))
                        .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top))
                        .with(ObjectAnimator
                                .ofFloat(expandedImageView, View.SCALE_X, startScaleFinal))
                        .with(ObjectAnimator
                                .ofFloat(expandedImageView, View.SCALE_Y, startScaleFinal));
                set.setDuration(mShortAnimationDuration);
                set.setInterpolator(new DecelerateInterpolator());
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        thumbView.setAlpha(1f);
                        expandedImageView.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {
                        thumbView.setAlpha(1f);
                        expandedImageView.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }
                });
                set.start();
                mCurrentAnimator = set;


    }
}

布局:

<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="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView style="?android:textAppearanceSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/message_zoom_touch_expand" />

        <!-- This is an example layout containing thumbnail image buttons that, when pressed,
             zoom in to show more detail. All of the zooming and animation logic is in
             the ZoomActivity class. -->
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:orientation="horizontal">

            <!-- These buttons don't have any decorations (3D bevel, etc.), but it's still
                 important to show feedback on touch or focus. The custom
                 "ToughHighlightImageButton" ImageButton subclass helps achieve this by drawing
                 the standard system "pressed" and "focused" overlay upon user interaction. -->

                  <FrameLayout
                android:id="@+id/thumb_button_1"
                android:layout_width="100dp"
                android:layout_height="75dp"
 android:background="@android:color/holo_orange_light"
                android:contentDescription="@string/description_image_2" />
            <FrameLayout
                android:id="@+id/thumb_button_2"
                android:layout_width="100dp"
                android:layout_height="75dp"
 android:background="@android:color/darker_gray"
                android:contentDescription="@string/description_image_2" />

        </LinearLayout>

    </LinearLayout>

    <!-- This initially-hidden ImageView will hold the expanded/zoomed version of the
         images above. Without transformations applied, it takes up the entire screen.
         To achieve the "zoom" animation, this view's bounds are animated from the
         bounds of the thumbnail buttons above, to its final laid-out bounds. The implementation
         of this animation is in the ZoomActivity class. -->
    <FrameLayout
        android:id="@+id/expanded_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible"
         android:background="@android:color/holo_blue_light" />

</FrameLayout>