Как сделать Rotate3dAnimation более плавным?

В моем приложении я использую Rotate3dAnimation для отображения карты Google. Код работает нормально, но анимация негладкая, некоторые строки также видны при повороте представления. Пожалуйста, взгляните на мой код и предложите мне, как сделать эту анимацию более гладкой? Предложение по достижению этого типа анимации любым другим эффективным способом высоко ценится. Введите описание изображения здесь

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

Мой xml-макет выглядит следующим образом:

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

Solutions Collecting From Web of "Как сделать Rotate3dAnimation более плавным?"

Я просто дам небольшой намек; Однако сейчас я так занят работой, что не могу это реализовать.

Этапы

  • Получить свой кэш чертежа Bitmap
  • Настройте свой контент на изображение только с помощью этого растрового изображения
  • Применить анимацию к этому представлению изображения
  • В конце анимации установите свой контент

Полагаю, это максимизирует производительность.

Я попытаюсь позже написать код.

КОД

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

Я сделал анимацию следующим образом. У меня были те же проблемы. Итак, предложения: – сделайте xml-макет максимально простым, вы можете протестировать его с помощью инструмента Hierarchy View в android. Этот инструмент показывает время построения и рисования лаутов; – изображения на макете должны иметь такой низкий вес, насколько это возможно; – используйте аппаратное ускорение, если ваше устройство поддерживает его (в манифесте):

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

– Я заметил еще одно интересное поведение. Если я вызываю некоторый код в методе onAnimationEnd (анимационная анимация), анимация замерзает на короткое время. Эта проблема была решена с помощью следующей конструкции:

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

Для создания анимации я использовал тот же код ( Rotate3dAnimation ). Для вызова анимации (основное отличие заключается в использовании параметра 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); } 

IsHardwareAcceleartionNotSupported () проверяет версию ОС. В моем проекте я отключил ускорение для смартфонов. В 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()); } } 

И еще одна проблема. Если анимация скрывается, когда экран поворачивается на 90 градусов, это проблема камеры. В этом случае мы должны поместить изображение дальше от зрителя.

  • И еще один трюк – иногда я устанавливаю паузу до начала анимации:

     animation.setStartOffset(100); 

Одним из вариантов для 3D-анимации (не OpenGL) для Android является реализация анимаций в методе getChildStaticTransform ViewGroup с использованием классов graphics.Camera и Matrix .

В широком смысле это делается следующим образом:

  • Расширьте ViewGroup или его подкласс.

  • В конструкторах установите staticTransformationEnabled в true:

      setStaticTransformationsEnabled(true); 
  • Переопределить защищенный метод getChildStaticTransformation (View view, Transformation t).

  • В getChildStaticTransformation используйте graphics.Camera для поворота View в соответствии с вашим изображением.

  • Получите матрицу камеры и настройте ее, чтобы центрировать положение камеры на экране.

Например, так выглядит 3D-перевод в 3d-каруселе Игоря Кушнарева:

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

Вот еще несколько примеров кода о том, как использовать graphics.Camera getChildStaticTransformation и Matrix в getChildStaticTransformation :

  • ViewPager3d от Inovex. Этот проект интересен тем, что если вы запускаете его как есть, 3D-анимация не является гладкой (на Galaxy S2). Напоследок, если вы разделите его на анимацию внекадровой / матричной перемотки, но сохраните полученные 3D-эффекты getChildStaticTransformation с помощью камеры и матрицы, 3D-эффекты будут плавными.

  • CoverFlow от Нила Дэвиса.

Я не могу полностью понять ур, но, по словам меня,

Ключом к плавной прокрутке Rotate3dAnimation является сохранение основной нити приложения (потока пользовательского интерфейса) без тяжелой обработки. Убедитесь, что вы производите доступ к диску, доступ к сети или SQL-доступ в отдельном потоке.

Эта ссылка предназначена для listview Rotate3dAnimation …