Анимация для перехода между представлениями с вращением по оси z с восприятием глубины

Я пытаюсь создать анимацию для перехода между двумя представлениями, обе из которых – ExpandableListViews. Вид, который я хочу, описан на изображении ниже.

Я попытался использовать shrink_to_middle и grow_from_middle в качестве анимации out / in моего ViewAnimator – и это близко, но не совсем правильно – с моим текущим сжатием / увеличением, по мере того, как происходит анимация, как правый, так и левый края представлений Той же высоты, которая не дает никакой глубины анимации.

Я не уверен, как лучше объяснить, что я хочу, поэтому я нарисовал изображение, но здесь все равно … Я хочу иметь 3-мерный взгляд на анимацию, где вид повернут по оси z , Предполагая, что мы используем простую анимацию shrink_to_middle и grow_from_middle в качестве отправной точки (которая не обеспечивает трехмерный вид.) Чтобы обеспечить трехмерный вид, анимация out будет иметь правый край, постепенно уменьшающийся по мере того, как представление сжимается до средний; В анимации левый край будет постепенно увеличиваться по мере того, как вид растет с середины.

Изображения с 1 по 4 представляли собой анимацию out (для просмотра # 1), а изображения 5-8 – в анимации (для просмотра № 2)

Анимация для перехода между видами

Заранее спасибо.

Изменить : FYI. Вот моя текущая усадка в середине и рост из средних анимационных xml-файлов

shrink_to_middle.xml

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:interpolator="@android:anim/linear_interpolator" android:fromXScale="1.0" android:toXScale="0.0" android:fromYScale="1.0" android:toYScale="1.0" android:fillAfter="false" android:duration="500" /> <translate android:fromXDelta="0" android:toXDelta="50%" android:duration="500" /> </set> 

grow_from_middle.xml

 <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:interpolator="@android:anim/linear_interpolator" android:fromXScale="0.0" android:toXScale="1.0" android:fromYScale="1.0" android:toYScale="1.0" android:fillAfter="false" android:startOffset="200" android:duration="500" /> <translate android:fromXDelta="50%" android:toXDelta="0" android:startOffset="200" android:duration="500" /> </set> 

Solutions Collecting From Web of "Анимация для перехода между представлениями с вращением по оси z с восприятием глубины"

Rotate3dAnimation – это ответ. Он находится в папке SDK образцов. Я использую анимацию от 0 до -90 и в анимации от 90 до 0, и она отлично работает.

Я должен был сделать почти то же самое. Единственное отличие в том, что мне пришлось вращать MapView . Может быть, слишком поздно ответить на этот вопрос, но я думаю, что это может быть полезно для других. Используйте Rotate3dAnimation следующим образом.

 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> 

Для примера анимации 3D-вращения вы можете увидеть в FlipAnimationExample . Но вы не должны использовать этот аниматор, если ваши взгляды тяжелы, потому что он делает поворот не гладким, как я вижу.

Для получения дополнительной анимации вы можете легко найти в своем приложении « Android UI Patterns » в Home> Animation & Effect.