2012-06-13 27 views
13

En mi aplicación estoy usando Rotate3dAnimation para mostrar un mapa de Google. El código funciona bien, pero la animación no es uniforme, algunas líneas también son visibles mientras se gira la vista. Por favor, eche un vistazo a mi código y sugiérame cómo puedo hacer que esta animación sea más fluida. La sugerencia para lograr este tipo de animación de cualquier otra manera eficiente es muy apreciada. enter image description here¿Cómo hacer que Rotate3dAnimation sea más suave?

public class EventsActivity extends MapActivity implements DialogInterface.OnDismissListener { 

     private EventsItemModel  eventsItemModel; 
     private Integer    eventItemId; 
     private Integer    eventCategoryId; 
     private static MapOverlay mapOverlay; 
     Drawable     marker; 
     Context      context; 
     private static String  MY_LOCATION = "My Location"; 
     private ViewGroup   mContainer; 
     private ImageView   mImageView; 
     private MapView    mMapView; 
     private static boolean  isFlipped = false; 

     @Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.event_item_detail); 
      mContainer = (ViewGroup) findViewById(R.id.event_container); 
      // Since we are caching large views, we want to keep their cache 
      // between each animation 
      mContainer.setPersistentDrawingCache(ViewGroup.PERSISTENT_ANIMATION_CACHE); 
      mMapView = (MapView) findViewById(R.id.mapview); 
      mImageView = (ImageView) findViewById(R.id.mapPreview); 

      mImageView.setOnClickListener(new OnClickListener() { 

       @Override 
       public void onClick(View v) { 
        isFlipped = true; 
        applyRotation(1, 0, 90); 
       } 
      }); 

      try { 
       eventCategoryId = getIntent().getIntExtra(AppConstants.EVENT_CATEGORY, 0); 
       eventItemId = getIntent().getIntExtra(AppConstants.EVENT_ID, 0); 
      } 
      catch (Exception e) { 
       e.printStackTrace(); 
      } 

     } 

     public void onResume() { 
      super.onResume(); 
      WeakReference<EventsActivity> weakContext = new WeakReference<EventsActivity>(this); 
      EventsAsyncTask task = new EventsAsyncTask(weakContext); 
      task.execute(eventItemId, eventCategoryId); 
     } 

     public void onTaskComplete(EventsItemModel eiModel) { 
      this.eventsItemModel = eiModel; 
      TextView calTitle = (TextView) findViewById(R.id.news_title); 
      TextView eventTitle = (TextView) findViewById(R.id.cal_event_title); 
      TextView calDate = (TextView) findViewById(R.id.cal_date); 
      TextView calTime = (TextView) findViewById(R.id.cal_time); 
      TextView calAddress = (TextView) findViewById(R.id.cal_address); 
      TextView calDescription = (TextView) findViewById(R.id.cal_description); 

      try { 
       calTitle.setText(eventsItemModel.getEventsCategory().getTitle()); 
       calTitle.setVisibility(View.VISIBLE); 
       eventTitle.setText(eventsItemModel.getEventTitle()); 
       calDate.setText(eventsItemModel.getFormattedDateRange()); 
       // TODO:Format start and end time 
       calTime.setText("Time: " + eventsItemModel.getFormattedStartTime() + " - " + eventsItemModel.getFormattedEndTime()); 
       calAddress.setText(eventsItemModel.getAddress()); 
       calDescription.setText(eventsItemModel.getDescription()); 
       System.out.println("<<<<<<<<<EventsActivity>>>>>>>>> isRead? " + eventsItemModel.getReadUnread()); 
       eventsItemModel.setReadUnread(true); 
       System.out.println("<<<<<<<<<<EventsActivity>>>>>>>>>> isRead? " + eventsItemModel.getReadUnread()); 
      } 
      catch (Exception e) { 
       e.printStackTrace(); 
      } 

      mMapView.setBuiltInZoomControls(true); 
      setMapParameters(); 
      createItemizedOverlay(); 
      setLocationMarker(createMarker(R.drawable.location_marker)); 
      showLocationPointOnMap(); 
     } 

     @Override 
     public void onDismiss(DialogInterface dialog) { 

     } 

     @Override 
     protected boolean isRouteDisplayed() { 
      return false; 
     } 

     public void createItemizedOverlay() { 
      mapOverlay = new MapOverlay(this); 
     } 

     public void setLocationMarker(Drawable marker) { 
      mapOverlay.setLocationMarker(marker); 
     } 

     public void showLocationPointOnMap() { 

      GeoPoint geoPoint = new GeoPoint(0, 0); 
      if (eventsItemModel != null && eventsItemModel.getLatitude() != null && eventsItemModel.getLatitude().length() > 0 && eventsItemModel.getLongitude() != null 
        && eventsItemModel.getLongitude().length() > 0) { 
       try { 
        geoPoint = new GeoPoint((int) (Double.parseDouble(eventsItemModel.getLatitude()) * 1E6), (int) (Double.parseDouble(eventsItemModel.getLongitude()) * 1E6)); 
       } 
       catch (NumberFormatException e) { 
        e.printStackTrace(); 
       } 
       OverlayItem item = new OverlayItem(geoPoint, MY_LOCATION, null); 
       mapOverlay.addItem(item); 
       mMapView.getOverlays().add(mapOverlay); 

       // move to location 
       mMapView.getController().animateTo(geoPoint); 
       // redraw map 
       mMapView.postInvalidate(); 
      } 

     } 

     public void setStreetView(boolean isStreetView) { 
      mMapView.setStreetView(isStreetView); 
     } 

     public void setSatelliteView(boolean isSatelliteView) { 
      mMapView.setSatellite(isSatelliteView); 
     } 

     public void setZoom(int zoomLevel) { 
      mMapView.getController().setZoom(zoomLevel); 
     } 

     private void setMapParameters() { 
      // setStreetView(true); 
      // setSatelliteView(false); 
      setZoom(17); 
     } 

     private Drawable createMarker(int iconID) { 
      // Initialize icon 
      Drawable icon = getResources().getDrawable(iconID); 
      icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); 
      return icon; 
     } 

     @Override 
     protected void onStop() { 
      // TODO Auto-generated method stub 
      super.onStop(); 
     } 

     @Override 
     protected void onPause() { 
      // TODO Auto-generated method stub 
      super.onPause(); 
     } 

     /** 
     * Setup a new 3D rotation on the container view. 
     * 
     * @param position 
     *   the item that was clicked to show a picture, or -1 to show the list 
     * @param start 
     *   the start angle at which the rotation must begin 
     * @param end 
     *   the end angle of the rotation 
     */ 
     private void applyRotation(int position, float start, float end) { 
      // Find the center of the container 
      final float centerX = mContainer.getWidth()/2.0f; 
      final float centerY = mContainer.getHeight()/2.0f; 

      // Create a new 3D rotation with the supplied parameter 
      // The animation listener is used to trigger the next animation 
      final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end, centerX, centerY, 310.0f, true); 
      rotation.setDuration(500); 
      rotation.setFillAfter(true); 
      rotation.setInterpolator(new AccelerateInterpolator()); 
      rotation.setAnimationListener(new DisplayNextView(position)); 

      mContainer.startAnimation(rotation); 
     } 

     /** 
     * This class listens for the end of the first half of the animation. It then posts a new action that effectively swaps the views when the container is rotated 90 degrees and thus invisible. 
     */ 
     private final class DisplayNextView implements Animation.AnimationListener { 
      private final int mPosition; 

      private DisplayNextView(int position) { 
       mPosition = position; 
      } 

      public void onAnimationStart(Animation animation) { 
      } 

      public void onAnimationEnd(Animation animation) { 
       mContainer.post(new SwapViews(mPosition)); 
      } 

      public void onAnimationRepeat(Animation animation) { 
       // Do nothing!! 
      } 
     } 

     /** 
     * This class is responsible for swapping the views and start the second half of the animation. 
     */ 
     private final class SwapViews implements Runnable { 
      private final int mPosition; 

      public SwapViews(int position) { 
       mPosition = position; 
      } 

      public void run() { 
       final float centerX = mContainer.getWidth()/2.0f; 
       final float centerY = mContainer.getHeight()/2.0f; 
       Rotate3dAnimation rotation; 

       if (mPosition > -1) { 
        mImageView.setVisibility(View.GONE); 
        mMapView.setVisibility(View.VISIBLE); 
        mMapView.requestFocus(); 

        rotation = new Rotate3dAnimation(-90, 180, centerX, centerY, 310.0f, false); 
        rotation.reset(); 
       } 
       else { 
        mMapView.setVisibility(View.GONE); 
        mImageView.setVisibility(View.VISIBLE); 
        mImageView.requestFocus(); 

        rotation = new Rotate3dAnimation(90, 0, centerX, centerY, 310.0f, false); 
       } 

       rotation.setDuration(100); 
       rotation.setFillAfter(true); 
       rotation.setInterpolator(new DecelerateInterpolator()); 

       mContainer.startAnimation(rotation); 
      } 
     } 

     @Override 
     public void onBackPressed() { 
      if (isFlipped) { 
       applyRotation(-1, 0, -90); 
       isFlipped = false; 
      } 
      else { 
       super.onBackPressed(); 
      } 
     } 

    } 

Mi diseño xml es el siguiente:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/event_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#426773" > 

    <include 
     android:id="@+id/news_header" 
     layout="@layout/news_header" /> 

    <TextView 
     android:id="@+id/cal_event_title" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_below="@id/news_header" 
     android:padding="5dp" 
     android:textColor="@android:color/white" 
     android:textSize="22sp" 
     android:textStyle="bold" 
     android:typeface="sans" /> 

    <RelativeLayout 
     android:id="@+id/date_time_container" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_below="@id/cal_event_title"> 

    <TextView 
     android:id="@+id/cal_date" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:padding="5dp" 
     android:textColor="@android:color/white" /> 

    <TextView 
     android:id="@+id/cal_time" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_below="@id/cal_date" 
     android:padding="5dp" 
     android:textColor="@android:color/white" /> 
    </RelativeLayout> 

    <ImageView 
     android:id="@+id/mapPreview" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_below="@id/cal_event_title" 
     android:layout_alignParentRight="true" 
     android:paddingRight="5dp"  
     android:clickable="true" 
     android:src="@drawable/ic_event_map" 
     android:onClick="showMap" 
     android:background="@drawable/textview_border" 
     android:layout_marginRight="5dp"/> 

    <TextView 
     android:id="@+id/cal_address" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_below="@id/date_time_container" 
     android:padding="5dp" 
     android:textColor="@android:color/white" 
     android:textSize="16sp" 
     android:textStyle="bold" 
     android:typeface="sans" /> 

    <ScrollView 
     android:id="@+id/scroll_description" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_below="@id/cal_address" 
     android:padding="5dp" 
     android:scrollbars="vertical" > 

     <RelativeLayout 
      android:id="@+id/map_container" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" > 

      <TextView 
       android:id="@+id/cal_description" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:textColor="@android:color/white"/> 
     </RelativeLayout> 

    </ScrollView> 

    <com.google.android.maps.MapView 
     android:id="@+id/mapview" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_centerInParent="true" 
     android:apiKey="your_google_api_key" 
     android:clickable="true" 
     android:visibility="gone" /> 

</RelativeLayout> 
+1

estoy usando Rotate3dAnimation en mi solicitud en este momento, y yo estoy frente a un problema similar. Hay un retraso en el que se saltan algunos cuadros. Investigando sobre esto, descubrí que durante la animación si se dispara gc, le quita unos pocos mseg, lo que hace que algunos cuadros salten. Este es el problema en mi caso. Así que compruebe si el recolector de basura es el alborotador. – FireAndIce

+0

este es mi problema también – Roylee

Respuesta

5

sólo voy a dar una pequeña pista; Sin embargo, en este momento estoy tan ocupado en el trabajo que no puedo implementar esto.

Los pasos son

  • conseguir su dibujo caché de mapa de bits
  • configurar su contenido a un imageview sólo con este mapa de bits
  • aplicar la animación a esta imageview
  • al final de la animación re establecer su contenido

Esto creo que maximizará el rendimiento.

Intentaré escribir algún código más tarde.

CÓDIGO

View longLivingReference; //keep a reference 
private void applyRotation(int position, float start, float end) { 
    longLivingReference = findViewById(R.id.event_container); 
    longLivingReference .setDrawingCacheEnabled(true); 
    Bitmap bitmapForAnimation = Bitmap.createBitmap(longLivingReference.getDrawingCache()); 
    ImageView iv = new ImageView(mContext); 
    iv = new ImageView(mContext); 
    iv.setImageBitmap(bitmapForAnimation); 
    setContentView(iv); 

    final float centerX = mContainer.getWidth()/2.0f; 
    final float centerY = mContainer.getHeight()/2.0f; 
    final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end, centerX, centerY, 310.0f, true); 
    rotation.setDuration(500); 
    rotation.setFillAfter(true); 
    rotation.setInterpolator(new AccelerateInterpolator()); 
    rotation.setAnimationListener(yourAnimationListener { 
     //whatever your AnimationListener is, you can call super.onAnimationEnd if needed 
     @Override 
     public void onAnimationEnd(Animation animation) { 
      setContentView(longLivingReference); 
     } 
    }); 
    iv.startAnimation(rotation); 
} 
+0

Sería de gran ayuda si también puedes publicar un código. – orchidrudra

+0

¿dónde está su event_container? Publicarlo –

+0

event_container es el diseño principal (un RelativeLayout) que contiene todas las demás vistas. Actualicé mi formato, de alguna manera no estaba mostrando RelativeLayout. Por favor, échale un vistazo. Gracias – orchidrudra

4

he hecho la animación como esta. Tenía los mismos problemas. Por lo tanto, sugerencias: : haga que el diseño de xml sea lo más simple posible; puede probarlo utilizando la herramienta de visualización de jerarquía en android. La herramienta muestra el tiempo de construcción y dibujo de laoyuts; - las imágenes en el diseño deben tener un peso tan bajo como sea posible; - utilizar la aceleración de hardware si su dispositivo es compatible con ella (en manifiesto):

<activity android:name=".ActivityName" android:hardwareAccelerated="true"/> 

- Me he dado cuenta de un comportamiento más interesing. Si invoco un código en el método Animation End (animación de animación), la animación se congela por un tiempo breve. Este problema estaba resuelto usando próxima construcción:

private static final int DELAY_AFTER_ANIMATION = 10; 

public void onAnimationEnd(Animation animation) { 
    new Handler().postDelayed(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      setData(); // do the heavy code here 
     } 
    }, DELAY_AFTER_ANIMATION); 
} 

Para construir animación que utiliza el mismo código (Rotate3dAnimation). Para las llamadas de animación (diferencia principal es mediante el parámetro isReverse):

método
public void apply3dRotation(float start, float end, AnimationListener listener, boolean isReverse) { 
    View view = getRotateView(); 
    if(view == null){ 
     return; 
    } 

    if (isHardwareAcceleartionNotSupported()){ 
     AndroidHelper.disableHardwareAccelerationOnView(view, this.getClass()); 
    } 

    final float centerX = view.getWidth()/2.0f; 
    final float centerY = view.getHeight()/2.0f; 

    Flip3dAnimation rotation; 

    rotation = new Flip3dAnimation(start, end, centerX, centerY, 310.0f, isReverse); 
    rotation.setDuration(ANIMATION_DURATION); 
    rotation.setFillAfter(true); 
    rotation.setInterpolator(new AccelerateInterpolator()); 

    if(listener != null){ 
     rotation.setAnimationListener(listener); 
    } 

    view.startAnimation(rotation); 
} 

isHardwareAcceleartionNotSupported() comprueba la versión del sistema operativo. En mi proyecto, deshabilité la aceleración para teléfonos inteligentes. En la clase AndroidHelper:

public static void disableHardwareAccelerationOnView(View view, Class c){ 
    try { 
     view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 
    } catch (Error e) { 
     Log.i(c.getSimpleName(), e.getMessage()); 
    } 
} 

Y un problema todavía. Si la animación se oculta cuando la pantalla gira 90 grados, es un problema de una cámara. En este caso, debemos ubicar la imagen más lejos del espectador.

  • Y un truco más - a veces establece la pausa antes de iniciar la animación:

    animation.setStartOffset(100); 
    
+0

Ok, voy a intentar su sugerencia, veamos qué pasa. – orchidrudra

+0

Agregué 'animation.setStartOffset (100);' y también acorté la duración de mi animación, ahora se ve mucho más rápido. Esas líneas se muestran con menos frecuencia. – orchidrudra

+0

Necesariamente prueba la aceleración de hardware –

1

Una opción para (no OpenGL) efectos de animación en 3D en Android es la implementación de las animaciones en un método ViewGroup getChildStaticTransform utilizando las clases graphics.Camera y Matrix.

En términos amplios se hace de esta manera:

  • Extender ViewGroup o una subclase de los mismos.

  • En los constructores, conjunto staticTransformationEnabled true:

    setStaticTransformationsEnabled(true); 
    
  • Override la getChildStaticTransformation método protegido (Ver vista, Transformación t).

  • En getChildStaticTransformation, utilice graphics.Camera para girar View según su imagen.

  • Get matriz de la cámara y ajustarla para centrar la posición de la cámara en la vista.

Por ejemplo, esto es como un efecto de conversión 3D se realiza en el 3d carousel por Igor Kushnarev:

protected boolean getChildStaticTransformation(View child, Transformation transformation) { 
    //... 
    // Center of the item 
    float centerX = (float)child.getWidth()/2, centerY = (float)child.getHeight()/2; 

    // Save camera 
    mCamera.save(); 

    // Translate the item to it's coordinates 
    final Matrix matrix = transformation.getMatrix(); 
    mCamera.translate(((CarouselImageView)child).getX(), 
      ((CarouselImageView)child).getY(), 
      ((CarouselImageView)child).getZ()); 

    // Get the camera's matric and position the item 
    mCamera.getMatrix(matrix); 
    matrix.preTranslate(-centerX, -centerY); 
    matrix.postTranslate(centerX, centerY); 

    // Restore camera 
    mCamera.restore();  

    return true; 
}  

Éstos son algunos ejemplos más de código sobre cómo utilizar graphics.Camera y Matrix en getChildStaticTransformation:

  • ViewPager3d de Inovex. Este proyecto es interesante porque si lo ejecuta como está, la animación 3D no es uniforme (en un Galaxy S2). Hoverever, si lo despojas de las animaciones de sobrecritura que no son de cámara/matriz pero mantienes los efectos 3D de getChildStaticTransformation con la cámara y la matriz, los efectos en 3D son suaves.

  • CoverFlow de Neil Davies.

+0

Gracias, voy a intentar sus sugerencias. – orchidrudra

0

No puedo entender ur pregunta por completo, pero en mi opinión,

La clave para una Rotate3dAnimation sin problemas de desplazamiento es mantener el hilo principal de la aplicación (el hilo de interfaz de usuario) libre de procesamiento pesado. Asegúrese de tener acceso a disco, acceso a la red o acceso SQL en un hilo separado.

This enlace isfor Rotate3dAnimation vista de lista ...

Cuestiones relacionadas