2012-06-13 38 views
13

Nella mia app sto usando Rotate3dAnimation per mostrare una mappa di Google. Il codice funziona bene, ma l'animazione non è liscia, alcune linee sono visibili mentre ruotano la vista. Si prega di dare un'occhiata al mio codice e suggerirmi come posso rendere questa animazione più agevole? Il suggerimento per realizzare questo tipo di animazione in qualsiasi altro modo efficiente è molto apprezzato. enter image description hereCome rendere Rotate3dAnimation più agevole?

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(); 
      } 
     } 

    } 

mio layout XML è la seguente:

<?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

sto usando Rotate3dAnimation nella mia domanda in questo momento, e sto affrontando problema simile. C'è un ritardo in cui vengono saltati alcuni fotogrammi. Facendo ricerche su di esso, ho scoperto che durante l'animazione, se gc viene sparato, ci vogliono pochi msec, il che porta a saltare alcuni fotogrammi. Questo è il problema nel mio caso. Quindi controlla se il garbage collector è il troublemaker. – FireAndIce

+0

anche questo è il mio problema – Roylee

risposta

5

mi limiterò a dare un piccolo suggerimento; tuttavia in questo momento sono così impegnato al lavoro che non posso implementarlo.

I passi sono

  • ottenere il disegno di cache bitmap
  • impostato sul suo sito web a un imageview solo con questo bitmap
  • applicare l'animazione a questo imageview
  • alla fine dell'animazione ri impostare il contenuto

Credo che massimizzerà le prestazioni.

Proverò a scrivere del codice più tardi.

CODICE

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

Sarebbe di grande aiuto se potessi pubblicare anche del codice. – orchidrudra

+0

dove sei event_container? Postalo –

+0

event_container è il layout principale (un RelativeLayout) che contiene tutte le altre viste. Ho aggiornato la mia formattazione, in qualche modo non stavo mostrando RelativeLayout. Per favore, dai un'occhiata. Grazie – orchidrudra

4

ho fatto l'animazione come questo. Ho avuto gli stessi problemi. Quindi, suggerimenti: - rendi il layout xml il più semplice possibile, puoi testarlo usando lo strumento Hierarchy View in Android. Lo strumento mostra il tempo di costruire e disegnare le lance; - le immagini sul layout dovrebbero avere il peso più basso possibile; - utilizzare l'accelerazione hardware se il dispositivo lo supporta (nel manifesto):

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

- ho notato un altro comportamento interesing. Se chiamo un codice nel metodo onAnimationEnd (Animation animazione), l'animazione si blocca per un breve periodo. Questo problema ero risolto utilizzando successiva costruzione:

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); 
} 

costruire animazione I usato lo stesso codice (Rotate3dAnimation). Per chiamare l'animazione (differenza principale sta usando il parametro isReverse):

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); 
} 

metodo isHardwareAcceleartionNotSupported() controlla la versione del sistema operativo. Nel mio progetto ho disabilitato l'accelerazione per gli smartphone. In classe 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()); 
    } 
} 

E un problema ancora. Se l'animazione si nasconde quando lo schermo ruota di 90 gradi, è un problema di una fotocamera. In questo caso dovremmo posizionare l'immagine più lontano dallo spettatore.

  • E un altro trucco - a volte ho impostato la pausa prima dell'inizio dell'animazione:

    animation.setStartOffset(100); 
    
+0

Ok, proverò il tuo suggerimento, vediamo cosa succede. – orchidrudra

+0

Ho aggiunto 'animation.setStartOffset (100);' e anche abbreviare la durata della mia animazione, ora sembra molto più veloce. Quelle linee stanno mostrando meno frequentemente. – orchidrudra

+0

Necessariamente provare l'accelerazione hardware –

1

Una delle possibilità per (non-OpenGL) effetti di animazione 3D su Android è quello di attuare le animazioni in un metodo getChildStaticTransform di ViewGroup utilizzando le classi graphics.Camera e Matrix.

In termini generali si è fatto in questo modo:

  • Extend ViewGroup o una sottoclasse di esso.

  • Nei costruttori, impostata su true staticTransformationEnabled:

    setStaticTransformationsEnabled(true); 
    
  • sovrascrivere il metodo getChildStaticTransformation protetta (Panorama vista, Trasformazione t).

  • In getChildStaticTransformation, utilizzare graphics.Camera per ruotare lo View come da immagine.

  • Prendi la matrice della telecamera e regolala per centrare la posizione della telecamera sulla vista.

Ad esempio, questo è il modo in cui un effetto cambio 3D è fatto in 3d carousel di 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; 
}  

Ecco alcuni esempi di più di codice su come utilizzare graphics.Camera e Matrix in getChildStaticTransformation:

  • ViewPager3d di Inovex. Questo progetto è interessante perché se lo si esegue così com'è, l'animazione 3d non è liscia (su un Galaxy S2). Hoverever, se lo si spoglia delle animazioni overscroll non-camera/matrix ma si mantengono gli effetti 3d getChildStaticTransformation fatti con camera e matrice, gli effetti 3d sono fluidi.

  • CoverFlow di Neil Davies.

+0

Grazie, proverò i tuoi suggerimenti. – orchidrudra

0

non riesco a capire completamente, ma secondo me ur domanda,

La chiave per una Rotate3dAnimation senza problemi di scorrimento è quello di mantenere thread principale dell'applicazione (thread UI) libero dalla lavorazione pesante. Assicurati di fare qualsiasi accesso al disco, accesso alla rete o accesso SQL in un thread separato.

This collegamento isfor ListView Rotate3dAnimation ...

Problemi correlati