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

Rya*_*anM 61 layout animation android imageview

我正在尝试在我的应用程序中为一个简单的ImageView设置动画,我希望它从屏幕底部滑入并进入静止位置,其中视图的顶部50px离开屏幕顶部(例如最终位置)在X中,ImageView应该是-50px.我曾尝试使用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>
Run Code Online (Sandbox Code Playgroud)

动画:

<?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>
Run Code Online (Sandbox Code Playgroud)

提前致谢.

Rya*_*anM 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

新的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)));
    }
}
Run Code Online (Sandbox Code Playgroud)

布局(/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>
Run Code Online (Sandbox Code Playgroud)

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="quickplay_offset">50dp</dimen>
</resources>
Run Code Online (Sandbox Code Playgroud)

动画(/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>
Run Code Online (Sandbox Code Playgroud)

该程序现在完全符合我的要求.整个布局从底部的屏幕开始,在1秒内滑入并进入休息,其中布局的顶部实际上是离屏幕顶部50px(即LL.getTop() = -50),并且布局的底部位于底部屏幕(即LL.getBottom() = 530 = 480 + 50).


小智 31

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

android:layout_marginTop="-40dp"
Run Code Online (Sandbox Code Playgroud)

  • 负边距可用于RelativeLayout 和LinearLayout,但不适用于ConstraintLayout;这是根据谷歌 Android 图形团队负责人 Romain Guy 的说法:/sf/answers/747150071/ (4认同)

esi*_*ver 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);
Run Code Online (Sandbox Code Playgroud)

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

不要直接使用layout()方法 - Android将随后调用以使随机原因使视图无效,并且只有layoutParams在invalidate调用中保持不变.如果您很好奇,请查看此文件的904到第912行,了解为什么必须修改layoutParams.

  • 警告:您不能在onCreate()中使用此代码,因为myView.getWidth()将始终返回0,因为视图尚未设置.这篇文章的前两个答案为您提供了两种获取视图宽度的策略:http://stackoverflow.com/questions/4142090/how-do-you-to-retrieve-dimensions-of-a-view-的getHeight和 - 的getWidth-总是-R?RQ = 1 (3认同)

Ste*_*ley 9

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

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

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

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

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

您可以在我对动画问题的其他答案中看到一些我的意思:关于使用SurfaceView有用性的基本回复以及要使用的循环示例.注意:第二个问题是旋转,因此我谈到的一些困难与你无关.祝好运!


Pab*_*rra 6

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">
Run Code Online (Sandbox Code Playgroud)