Android - 如何在屏幕外定位View?

时间:2010-03-31 16:54:27

标签: android layout animation imageview

我正在尝试在我的应用程序中为一个简单的ImageView设置动画,我希望它从屏幕底部滑入并进入静止位置,其中视图的顶部50px离开屏幕顶部(例如ImageView的最终位置应为-50px(X)。我曾尝试使用AbsoluteLayout来做到这一点,但这实际上切断了ImageView的前50px,使得前50px永远不会被渲染。我需要让ImageView的前50px可见/渲染,同时它是动画,然后让它稍微离开屏幕。我希望我已经解释得那么好了。

以下是我目前正在使用的布局和幻灯片动画(目前这不会渲染ImageView的前50px):

布局:

<?xml version="1.0" encoding="utf-8"?>
   <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_height="fill_parent" 
      android:layout_width="fill_parent" 
      android:id="@+id/QuickPlayClipLayout">
      <ImageView android:id="@+id/Clip"
         android:background="@drawable/clip" 
         android:layout_width="fill_parent" 
         android:layout_height="wrap_content" 
         android:layout_y="-50dp">
      </ImageView>
   </AbsoluteLayout>

动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
   <translate android:fromYDelta="100%p" 
       android:toYDelta="0"
       android:duration="1000"/>
   <alpha android:fromAlpha="0.0" 
       android:toAlpha="1.0"
       android:duration="1000" />
</set>

提前致谢。

6 个答案:

答案 0 :(得分:33)

我找到了一个易于实现的解决方案。它涉及修改布局和夸大布局的活动......见下文:

活动(QuickPlay.java):

public class QuickPlay extends Activity implements AnimationListener
{
    private ImageView myImageView;
    private LinearLayout LL;

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

        myImageView = (ImageView) this.findViewById(R.id.Clip);
        LL = (LinearLayout) this.findViewById(R.id.QuickPlayClipLayout);

        //finally
        Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_in_quickplay);
        anim.setAnimationListener(this);
        LL.startAnimation(anim);
    }
    @Override
    public void onAnimationEnd(Animation animation){}

    @Override
    public void onAnimationRepeat(Animation animation){}

    @Override
    public void onAnimationStart(Animation animation)
    {
        // This is the key...
        //set the coordinates for the bounds (left, top, right, bottom) based on the offset value (50px) in a resource XML
        LL.layout(0, -(int)this.getResources().getDimension(R.dimen.quickplay_offset), 
                LL.getWidth(), LL.getHeight() + (int)this.getResources().getDimension(R.dimen.quickplay_offset));
    }
}

New LinearLayout(CustomLinearLayout.java):

public class CustomLinearLayout extends LinearLayout
{
    private Context myContext;

    public CustomLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        myContext = context;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec+((int)myContext.getResources().getDimension(R.dimen.quickplay_offset)));
    }
}

布局(/res/layout/quick_play_screen.xml):

<?xml version="1.0" encoding="utf-8"?>
   <com.games.mygame.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_height="fill_parent" 
      android:layout_width="fill_parent" 
      android:id="@+id/QuickPlayClipLayout">
      <ImageView android:id="@+id/Clip"
         android:background="@drawable/clip" 
         android:layout_width="fill_parent" 
         android:layout_height="wrap_content">
      </ImageView>
   </com.games.mygame.CustomLinearLayout>

资源(/res/values/constants.xml):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="quickplay_offset">50dp</dimen>
</resources>

动画(/res/anim/slide_in_quickplay.xml):

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
   <translate android:fromYDelta="100%p" 
       android:toYDelta="0"
       android:duration="1000"/>
   <alpha android:fromAlpha="0.0" 
       android:toAlpha="1.0"
       android:duration="1000" />
</set>

该程序现在正是我需要它做的事情。整个布局从底部的屏幕开始,在1秒内滑入并进入休息,其中布局的顶部实际上离屏幕顶部50px(即LL.getTop() = -50)并且布局的底部是停留在屏幕的底部(即LL.getBottom() = 530 = 480 + 50)。

答案 1 :(得分:30)

要在屏幕外定位我的视图,我使用了以下代码:

View myView = /* view you want to position offscreen */
int amountOffscreen = (int)(myView.getWidth() * 0.8); /* or whatever */
boolean offscreen = /* true or false */


int xOffset = (offscreen) ? amountOffscreen : 0;
RelativeLayout.LayoutParams rlParams = 
    (RelativeLayout.LayoutParams)myView.getLayoutParams();
rlParams.setMargins(-1*xOffset, 0, xOffset, 0);
myView.setLayoutParams(rlParams);

此代码将通过amountOffscreen将myView定位在屏幕外,在这种情况下,屏幕上80%的视图放在屏幕上,只留下20%的屏幕。

不要直接使用layout()方法 - 由于随机原因Android会进行后续调用以使视图无效,并且只有layoutParams在invalidate调用中保持不变。如果您感到好奇,请查看第904 to 912 of this file行,了解为什么必须修改layoutParams。

答案 2 :(得分:28)

相反,我们可以简单地给layout_margin(上/左/右/下)提供负值 例如:如果您希望从屏幕顶部关闭视图,则可以指定

android:layout_marginTop="-40dp"

答案 3 :(得分:9)

如果你跳到使用Canvas,这很容易做到;那些支持毫无困难地拔出屏幕。但是,实施起来会更复杂。您需要实现自定义View并在代码中编写自己的动画。从本质上讲,这归结为简单的2D图形处理,而不是使用内置XML动画的视图。 可能有办法用XML来做,但我对画布更熟悉。在代码中处理这是如何处理的一个非常好的地方是SDK附带的Lunar Lander示例游戏。

您需要遵循的步骤大致是:

  1. 使用<your.package.AnimatingView>之类的内容在XML文件中放置自定义视图,将其大小设置为fill-parent。

  2. 然后定义一个AnimatingView类,extends SurfaceView and implements SurfaceHolder.Callback。 (这使您可以立即访问绘图Canvas而不是使用invalidate()方法。这很重要因为invalidate()仅在线程空闲时刷新,例如在循环结束时刷新。实现你的动画,你需要立即绘制它。)

  3. 然后,您可以实现一个循环,在整个屏幕上绘制您的运动图像。循环需要从绘制整个背景开始(因为画布不会自动擦除),然后根据已经过去的时间在新位置绘制图像。例如,如果您希望动画需要1秒钟,那么您就知道如果已经过了200ms,那么视图应该只从其起始位置移动到最终位置的200/1000或1/5

  4. 您可以在我对动画问题的其他答案中看到一些我的意思:关于usefulness of using SurfaceViewexample of the loop to use的基本回复。注意:第二个问题是关于旋转,因此我谈到的一些困难与你无关。祝你好运!

答案 4 :(得分:3)

使用android:translationXandroid:translationY

<RelativeLayout
        android:translationX="-600dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">

答案 5 :(得分:2)

我有一个带有孩子的视图组,并将视图从底部拖入屏幕 - 有点像抽屉。然后,我放手,如果视图组上边距位于屏幕的上半部分,我会在用户释放触摸后将其设置为顶部。

当发生这种情况时,视图组子项中的图像会在动画过程中被裁剪,但会在动画后显示。

问题:viewgroup的高度是wrap_content。我通过将高度设置为在动画开始之前从屏幕伸展的值来解决这个问题。