programacion - Diseño de animación Android
manual de programacion android pdf (3)
Quiero animar dos diseños diferentes.
Ejemplo
Ya tengo la animación como quiero, solo quiero animar un diseño XML diferente. Hay una clase LayoutAnimationController, pero realmente no sé cómo usarla. ¿Puede alguien señalarme en la dirección correcta, con un ejemplo o una buena explicación?
Aquí está el código que uso para animar.
TranslateAnimation slide = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 300f, 0,0 );
slide.setAnimationListener(AL);
slide.setFillAfter(true);
slide.setDuration(1000);
parentlayout.startAnimation(slide);
Actualización Debido a los muchos votos positivos, decidí poner un proyecto de ejemplo en un repositorio de Git. Ver mis respuestas para el enlace.
Ok Después de pasar 2 días leyendo sobre problemas similares y cómo la gente los resolvió finalmente pude crear lo que quería. No pude hacerlo con 2 archivos XML diferentes, pero dudo que no sea posible.
Encontré algunos problemas aunque
Una vez que finalizó la primera animación, no se pudo hacer clic en el botón. Esto se debe a que la animación muestra que todo se movió pero no actualiza el diseño, por lo que el botón sigue en la posición donde se inició la animación. Así que tuve que calcular la nueva posición del diseño.
Creo que leí en alguna parte que esto ya no es un problema en 3.0, pero corrígeme si me equivoco
Otra fue que cuando finalmente mi animación comenzó a funcionar de la manera que quería mi vista subyacente desapareció antes de que la animación finalizara porque invocaba view.setVisabilty(View.GONE);
. Ahora el problema era que cuando no invoqué ese método, la animación simplemente se cuelga por un segundo y luego tira a la posición final de la animación. Así que agregué una propiedad LinearLayout vacía (puede ser cualquier cosa), predeterminada en GONE, cuando la animación comienza a establecerse en Visible. cuando revierte la animación, configúrela nuevamente como desaparecida. después de hacer esto, la animación funcionaba como yo quería.
Y si está utilizando Rel, Linear o cualquier otro diseño. entonces no puedes apilar las vistas en orden Z, así que debes usar SurfaceView.
Así que aquí está main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<SurfaceView
android:id="@+id/surfaceView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:id="@+id/layout"
android:layout_width="220dp"
android:layout_height="fill_parent"
android:background="#ffee00"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/fake_layouy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" android:visibility="gone">
</LinearLayout>
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</RelativeLayout>
<RelativeLayout
android:id="@+id/layoutTwo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ff00ee"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" android:background="#ff0000" android:layout_margin="2dp">
<Button
android:id="@+id/button"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:text="slide" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
aquí está el código java
public class MenuAnimationActivity extends Activity {
private Button buttonSwitch;
private View subLayout;
private View topLayout;
private ListView subViewListView;
private String listViewDummyContent[]={"Android","iPhone","BlackBerry","AndroidPeople"};
private Display display;
private View fakeLayout;
private AnimationListener AL;
// Values for after the animation
private int oldLeft;
private int oldTop;
private int newleft;
private int newTop;
private int screenWidth;
private int animToPostion;
// TODO change the name of the animToPostion for a better explanation.
private boolean menuOpen = false;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
buttonSwitch = (Button)findViewById(R.id.button);
subLayout = (View) findViewById(R.id.layout);
topLayout = (View) findViewById(R.id.layoutTwo);
subViewListView=(ListView)findViewById(R.id.listView1);
fakeLayout = (View)findViewById(R.id.fake_layouy);
subViewListView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1 , listViewDummyContent));
display = getWindowManager().getDefaultDisplay();
screenWidth = display.getWidth();
int calcAnimationPosition = (screenWidth /3);
// Value where the onTop Layer has to animate
// also the max width of the layout underneath
// Set Layout params for subLayout according to calculation
animToPostion = screenWidth - calcAnimationPosition;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(animToPostion, RelativeLayout.LayoutParams.FILL_PARENT);
subLayout.setLayoutParams(params);
topLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
if (menuOpen == true) {
animSlideLeft();
}
}
return false;
}
});
buttonSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(menuOpen == false){
animSlideRight();
} else if (menuOpen == true) {
animSlideLeft();
}
}
});
AL = new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
buttonSwitch.setClickable(false);
topLayout.setEnabled(false);
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
if(menuOpen == true) {
Log.d("", "Open");
topLayout.layout(oldLeft, oldTop, oldLeft + topLayout.getMeasuredWidth(), oldTop + topLayout.getMeasuredHeight() );
menuOpen = false;
buttonSwitch.setClickable(true);
topLayout.setEnabled(true);
} else if(menuOpen == false) {
Log.d("","FALSE");
topLayout.layout(newleft, newTop, newleft + topLayout.getMeasuredWidth(), newTop + topLayout.getMeasuredHeight() );
topLayout.setEnabled(true);
menuOpen = true;
buttonSwitch.setClickable(true);
}
}
};
}
public void animSlideRight(){
fakeLayout.setVisibility(View.VISIBLE);
newleft = topLayout.getLeft() + animToPostion;
newTop = topLayout.getTop();
TranslateAnimation slideRight = new TranslateAnimation(0,newleft,0,0);
slideRight.setDuration(500);
slideRight.setFillEnabled(true);
slideRight.setAnimationListener(AL);
topLayout.startAnimation(slideRight);
}
public void animSlideLeft() {
fakeLayout.setVisibility(View.GONE);
oldLeft = topLayout.getLeft() - animToPostion;
oldTop = topLayout.getTop();
TranslateAnimation slideLeft = new TranslateAnimation(newleft,oldLeft,0,0);
slideLeft.setDuration(500);
slideLeft.setFillEnabled(true);
slideLeft.setAnimationListener(AL);
topLayout.startAnimation(slideLeft);
}
}
Hice algunas codificaciones adicionales para tocar vistas y esas cosas.
Y el resultado final
antes de la animación
después de la primera animación
Y después de la segunda animación de vuelta a la izquierda, muestra devoluciones como la primera imagen.
Todos esos mensajes que me ayudaron realmente merecen algo de crédito, pero no puedo encontrar ninguno de ellos.
Editar
GIT https://bitbucket.org/maikelbollemeijer/sidepanelswitcher
Actualización: https://github.com/jfeinstein10/SlidingMenu esta lib es compatible con Actionbar Sherlock.
espero que esto ayude
Tenía el requisito similar de hacer una animación de diseño como la aplicación de Facebook. Para hacer eso, hice un ViewGroup personalizado (llamado AnimationLayout). Espero que estos códigos ayuden.
AnimationLayout necesita dos hijos: barra lateral y contenido. (asignando @ + id / animation_sidebar y @ + id / animation_content a la correspondiente)
Este es el diseño xml, SideBar tiene un botón y una vista de lista. El contenido tiene una vista de texto y un botón (se une a una función de devolución de llamada).
<?xml version="1.0" encoding="utf-8"?>
<org.zeroxlab.widget.AnimationLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/animation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="@+id/animation_sidebar"
android:layout_width="200dip"
android:layout_height="match_parent"
android:background="#550000"
android:orientation="vertical"
>
<Button
android:id="@+id/button_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sidebar Button"
/>
<ListView
android:id="@+id/sidebar_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/animation_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#003300"
android:clickable="true"
>
<Button android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Content Button"
android:onClick="onClickButton"
/>
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="The Answer to Life, the Universe, and Everything -- is 42"
/>
</LinearLayout>
</org.zeroxlab.widget.AnimationLayout>
Esta es la actividad de prueba. Inicializa un ListView y se asigna como un Listener a AnimationLayout.
package test.julian.hello;
import org.zeroxlab.widget.AnimationLayout;
import android.app.Activity;
import android.app.ActivityManager;
import android.os.Bundle;
import android.widget.*;
import android.util.Log;
import android.view.View;
public class HelloAndroid extends Activity implements AnimationLayout.Listener {
ListView mList;
AnimationLayout mLayout;
String[] mStrings = {"a", "b", "c", "d", "e", "f", "g"};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.app_layout);
mLayout = (AnimationLayout) findViewById(R.id.animation_layout);
mLayout.setListener(this);
mList = (ListView) findViewById(R.id.sidebar_list);
mList.setAdapter(
new ArrayAdapter<String>(
this, android.R.layout.simple_list_item_multiple_choice
, mStrings));
mList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
public void onClickButton(View v) {
mLayout.toggleSidebar();
}
@Override
public void onSidebarOpened() {
Log.d("Foo", "opened");
}
@Override
public void onSidebarClosed() {
Log.d("Foo", "opened");
}
@Override
public boolean onContentTouchedWhenOpening() {
Log.d("Foo", "going to close sidebar");
mLayout.closeSidebar();
return true;
}
}
Este es el AnimationLayout.
/*
* Copyright (C) 2012 0xlab - http://0xlab.org/
*
* 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.
*
* Authored by Julian Chu <walkingice AT 0xlab.org>
*/
package org.zeroxlab.widget;
import test.julian.hello.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
public class AnimationLayout extends ViewGroup {
public final static int DURATION = 500;
protected boolean mOpened;
protected View mSidebar;
protected View mContent;
protected int mSidebarWidth = 150; // by default
protected Animation mAnimation;
protected OpenListener mOpenListener;
protected CloseListener mCloseListener;
protected Listener mListener;
protected boolean mPressed = false;
public AnimationLayout(Context context) {
this(context, null);
}
public AnimationLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onFinishInflate() {
super.onFinishInflate();
mSidebar = findViewById(R.id.animation_sidebar);
mContent = findViewById(R.id.animation_content);
if (mSidebar == null) {
throw new NullPointerException("no view id = animation_sidebar");
}
if (mContent == null) {
throw new NullPointerException("no view id = animation_content");
}
mOpenListener = new OpenListener(mSidebar, mContent);
mCloseListener = new CloseListener(mSidebar, mContent);
}
@Override
public void onLayout(boolean changed, int l, int t, int r, int b) {
/* the title bar assign top padding, drop it */
mSidebar.layout(l, 0, l + mSidebarWidth, 0 + mSidebar.getMeasuredHeight());
if (mOpened) {
mContent.layout(l + mSidebarWidth, 0, r + mSidebarWidth, b);
} else {
mContent.layout(l, 0, r, b);
}
}
@Override
public void onMeasure(int w, int h) {
super.onMeasure(w, h);
super.measureChildren(w, h);
mSidebarWidth = mSidebar.getMeasuredWidth();
}
@Override
protected void measureChild(View child, int parentWSpec, int parentHSpec) {
/* the max width of Sidebar is 90% of Parent */
if (child == mSidebar) {
int mode = MeasureSpec.getMode(parentWSpec);
int width = (int)(getMeasuredWidth() * 0.9);
super.measureChild(child, MeasureSpec.makeMeasureSpec(width, mode), parentHSpec);
} else {
super.measureChild(child, parentWSpec, parentHSpec);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!isOpening()) {
return false;
}
int action = ev.getAction();
if (action != MotionEvent.ACTION_UP
&& action != MotionEvent.ACTION_DOWN) {
return false;
}
/* if user press and release both on Content while
* sidebar is opening, call listener. otherwise, pass
* the event to child. */
int x = (int)ev.getX();
int y = (int)ev.getY();
if (mContent.getLeft() < x
&& mContent.getRight() > x
&& mContent.getTop() < y
&& mContent.getBottom() > y) {
if (action == MotionEvent.ACTION_DOWN) {
mPressed = true;
}
if (mPressed
&& action == MotionEvent.ACTION_UP
&& mListener != null) {
mPressed = false;
return mListener.onContentTouchedWhenOpening();
}
} else {
mPressed = false;
}
return false;
}
public void setListener(Listener l) {
mListener = l;
}
/* to see if the Sidebar is visible */
public boolean isOpening() {
return mOpened;
}
public void toggleSidebar() {
if (mContent.getAnimation() != null) {
return;
}
if (mOpened) {
/* opened, make close animation*/
mAnimation = new TranslateAnimation(0, -mSidebarWidth, 0, 0);
mAnimation.setAnimationListener(mCloseListener);
} else {
/* not opened, make open animation */
mAnimation = new TranslateAnimation(0, mSidebarWidth, 0, 0);
mAnimation.setAnimationListener(mOpenListener);
}
mAnimation.setDuration(DURATION);
mAnimation.setFillAfter(true);
mAnimation.setFillEnabled(true);
mContent.startAnimation(mAnimation);
}
public void openSidebar() {
if (!mOpened) {
toggleSidebar();
}
}
public void closeSidebar() {
if (mOpened) {
toggleSidebar();
}
}
class OpenListener implements Animation.AnimationListener {
View iSidebar;
View iContent;
OpenListener(View sidebar, View content) {
iSidebar = sidebar;
iContent = content;
}
public void onAnimationRepeat(Animation animation) {
}
public void onAnimationStart(Animation animation) {
iSidebar.setVisibility(View.VISIBLE);
}
public void onAnimationEnd(Animation animation) {
iContent.clearAnimation();
mOpened = !mOpened;
requestLayout();
if (mListener != null) {
mListener.onSidebarOpened();
}
}
}
class CloseListener implements Animation.AnimationListener {
View iSidebar;
View iContent;
CloseListener(View sidebar, View content) {
iSidebar = sidebar;
iContent = content;
}
public void onAnimationRepeat(Animation animation) {
}
public void onAnimationStart(Animation animation) {
}
public void onAnimationEnd(Animation animation) {
iContent.clearAnimation();
iSidebar.setVisibility(View.INVISIBLE);
mOpened = !mOpened;
requestLayout();
if (mListener != null) {
mListener.onSidebarClosed();
}
}
}
public interface Listener {
public void onSidebarOpened();
public void onSidebarClosed();
public boolean onContentTouchedWhenOpening();
}
}
Cuando SideBar se cerró, se ve así.
Cuando se abrió SideBar, se ve así.
Tomé la solución de walkingice ( https://github.com/walkingice/gui-sliding-sidebar ) y la agregué, haciendo un widget en el que la "barra lateral" puede entrar desde la parte superior o inferior, así como desde la izquierda o hacia la derecha. También puede especificar el ancho (o la altura) de la barra lateral como porcentaje del ancho (o alto) principal. La barra lateral puede estar estacionaria detrás de la vista de contenido principal o deslizarse hacia adentro.
El proyecto es por SolutionStream, y está disponible aquí: https://github.com/solutionstream/sidebarlayout
Es de código abierto (licencia Apache 2.0), por lo que puede consultar el código y usarlo (bajo la licencia), ya sea como ejemplo o directamente.
DIVULGACIÓN: El enlace de arriba es para un proyecto que creé en SolutionStream.