programacion - Android: ¿cómo posicionar la vista fuera de la pantalla?
manual de programacion android pdf (5)
Intento animar un ImageView simple en mi aplicación y quiero que se deslice desde la parte inferior de la pantalla y llegar a una posición de descanso donde los 50px superiores de la vista están fuera de la parte superior de la pantalla (por ejemplo, la posición final) de ImageView debe ser -50px en X). Intenté utilizar AbsoluteLayout para hacer esto, pero esto realmente corta los 50 píxeles superiores de ImageView de modo que los 50 píxeles superiores nunca se procesan. Necesito que los 50 píxeles superiores de ImageView sean visibles / renderizados mientras se animan y luego simplemente descansar ligeramente fuera de la pantalla. Espero haberlo explicado lo suficientemente bien.
Esto es lo que estoy usando actualmente como diseño y la animación deslizante (actualmente no representa los 50 píxeles superiores de ImageView):
Diseño:
<?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>
Animación:
<?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>
Gracias por adelantado.
Descubrí una solución a esto que debería ser fácil de implementar. Implica modificar el diseño y la Actividad inflando el diseño ... ver a continuación:
Actividad (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)));
}
}
Diseño (/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>
Recurso (/res/values/constants.xml):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="quickplay_offset">50dp</dimen>
</resources>
Animación (/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>
El programa ahora hace exactamente lo que necesito que haga. Todo el diseño comienza en la pantalla en la parte inferior, se desliza en 1 segundo y se detiene cuando la parte superior del diseño está a 50px de la parte superior de la pantalla (es decir, LL.getTop() = -50
) y la parte inferior el diseño descansa en la parte inferior de la pantalla (es decir, LL.getBottom() = 530 = 480 + 50
).
En su lugar, podemos dar valores negativos a layout_margin (Top / left / right / bottom), por ejemplo: si desea que su vista esté desactivada desde la parte superior de la pantalla, puede especificar
android:layout_marginTop="-40dp"
Esto es fácil de hacer si hace un salto para usar un Canvas
; aquellos soportan sacar la pantalla sin ningún problema. Sin embargo, será más complicado de implementar. Debería implementar una View
personalizada y escribir su propia animación en el código. Básicamente, esto se reduce a un simple manejo de gráficos 2D en lugar de Vistas usando animaciones XML integradas. Puede haber una forma de hacerlo con XML, pero estoy mucho más familiarizado con los lienzos. Un muy buen lugar para ver cómo se maneja esto en el código es el juego de ejemplo Lunar Lander que viene con el SDK.
A grandes rasgos, los pasos que deberá seguir son:
Coloque una vista personalizada en el archivo XML, usando algo como
<your.package.AnimatingView>
, estableciendo su tamaño para rellenar-principal.A continuación, defina una clase AnimatingView, que
extends SurfaceView and implements SurfaceHolder.Callback
. (Esto le da acceso inmediato al dibujoCanvas
lugar de utilizar el métodoinvalidate()
. Esto es importante porque invalidate () solo se actualiza cuando el hilo está inactivo, por ejemplo, al final del ciclo. Para implementar su animación, necesita tenerlo dibujando inmediatamente.)A continuación, puede implementar un bucle que dibuja su imagen en movimiento a través de la pantalla. El ciclo debe comenzar por dibujar todo el fondo (porque el lienzo no se borra automáticamente) y luego dibujar la imagen en su nueva posición en función del tiempo que ha pasado. Por ejemplo, si desea que su animación tarde 1 segundo, sabrá que si han transcurrido 200 ms, la vista solo debería haberse movido 200/1000, o 1/5, del camino desde su posición inicial hasta la posición final .
Puede ver algunos ejemplos de lo que quiero decir en mis otras respuestas a las preguntas de animación: respuesta básica acerca de la utilidad de usar SurfaceView y el ejemplo del ciclo a usar . Nota: la segunda pregunta fue sobre la rotación, y por lo tanto, algunas de las dificultades de las que hablé no serán relevantes para usted. ¡Buena suerte!
Para colocar mi vista fuera de la pantalla, utilicé el siguiente código:
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);
Este código posicionará a myView offscreen por amountOffscreen, que en este caso pone el 80% de la vista fuera de pantalla dejando solo el 20% en pantalla.
No utilice directamente el método layout (): Android realizará llamadas subsiguientes para invalidar su vista por motivos aleatorios y solo se conservarán los parámetros de diseño en las llamadas invalidadas. Si tiene curiosidad, revise las líneas 904 a 912 de este archivo para ver por qué tiene que modificar el layoutParams.
Tenía un grupo de visión con niños y arrastraba la vista desde la parte inferior de la pantalla, como un cajón. Luego solía soltar y si el margen superior del grupo de vistas se encontraba en la mitad superior de la pantalla, lo animaba a la parte superior después de que el usuario lo soltara.
Cuando esto ocurría, las imágenes de los hijos del grupo de visualización se recortaban durante la animación, pero luego se mostraban después de la animación.
El problema: la altura del grupo de visualización era wrap_content. Lo resolví estableciendo la altura en un valor que se extendía fuera de la pantalla antes de que comenzara la animación.