Я использую пользовательские растровые изображения в качестве значка маркеров на карте. когда пользователь щелкает любой маркер, я хочу иметь представление, соответствующее нажатому растровому изображению, и добавлять его как общий элемент к переходу фрагмента. но я не вижу никакого метода для извлечения растрового изображения из маркера. Итак, как начать переход общего элемента с маркера?
Android-как начать переход общего элемента из растрового изображения маркера?
Ответы (1)
Вкратце: используйте setTag()/getTag()
методы для сохранения / восстановления растрового изображения в объекте маркера и дополнительные ImageView
с этим растровым изображением в качестве общего элемента для переходов между фрагментами карты и деталей:
TL; DR;
Если вы используете пользовательские растровые изображения в качестве значка маркеров, вы можете сохранить их в _ 3_ объекты с _ 4_, а затем получить растровое изображение значка маркера в _ 5_. Но растрового изображения недостаточно для переходов общих элементов, потому что необходим объект класса View
выполнить это. Итак, вам нужно создать дополнительный View
(например, ImageView
) и использовать его как общий элемент для переходов между фрагментами карты и деталей.
Как правило, вам следует:
- При запуске приложения (в
MainActivity
):
- создать фрагмент карты с
ImageView
для выполнения перехода общего элемента; - создать фрагмент деталей с соответствующим
ImageView
для выполнения перехода общего элемента; - создавать анимацию перехода общих элементов;
- При создании маркера (во фрагменте карты):
- просто сохраните растровое изображение в объекте маркера.
- Когда пользователь нажимал на маркер,
во фрагменте карты:
- в извлечении сохраненного растрового изображения из объекта маркера;
- установить для полученного растрового изображения общий
ImageView
; - измените размер
ImageView
и переместите его так, чтобы он располагался точно над значком маркера; - скрыть значок маркера и показать
ImageView
со значком маркера вместо маркера; - поместите битовую карту маркера (и, например, описание) в подробный фрагмент с помощью аргументов;
- создать и запустить
FragmentTransaction
;
подробный фрагмент:
- получить битовую карту и описание маркера из аргументов и показать их на соответствующих
ImageView
иTextView
;
- Когда пользователь закрывает фрагмент сведений (во фрагменте карты),
- дождитесь окончания анимации перехода и покажите маркер / скрыть
ImageView
.
Наиболее сложной частью этого является создание общего представления внутри фрагмента карты, потому что SupportMapFragment
не имел такого элемента из коробки. Поэтому вам нужно создать пользовательский CustomSupportMapFragment
, который расширяет SupportMapFragment
и иметь дополнительные ImageView
для переходов общих элементов:
public class CustomSupportMapFragment extends SupportMapFragment {
private Bitmap mBitmap;
private float mY;
private float mX;
private RelativeLayout mRelativeLayout;
private ImageView mSharedImageView;
private Marker mMarker;
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View root = super.onCreateView(inflater, container, savedInstanceState);
mRelativeLayout = new RelativeLayout(root.getContext());
mRelativeLayout.addView(root, new RelativeLayout.LayoutParams(-1, -1));
mSharedImageView = new ImageView(root.getContext());
mSharedImageView.setId(View.generateViewId());
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
mSharedImageView.setLayoutParams(layoutParams);
mSharedImageView.setTransitionName("sharedImageView");
mRelativeLayout.addView(mSharedImageView);
return mRelativeLayout;
}
@Override
public void onStart() {
super.onStart();
if (mBitmap != null) {
mSharedImageView.setImageBitmap(mBitmap);
mSharedImageView.setX(mX);
mSharedImageView.setY(mY);
}
}
@Override
public void onStop() {
super.onStop();
mBitmap = ((BitmapDrawable)mSharedImageView.getDrawable()).getBitmap();
mX = mSharedImageView.getX();
mY = mSharedImageView.getY();
}
public void setSharedMarker(Marker marker) {
mMarker = marker;
}
public void setSharedViewInitialPosition(float x, float y) {
mSharedImageView.setX(x);
mSharedImageView.setY(y);
}
public void setSharedBitmap(Bitmap bitmap) {
mSharedImageView.setImageBitmap(bitmap);
}
public ImageView getSharedView() {
return mSharedImageView;
}
public void showMarker() {
if (mMarker != null) mMarker.setVisible(true);
}
}
Фрагмент деталей может быть таким типичным:
public class DetailsFragment extends Fragment {
private ImageView mImageView;
private TextView mTextView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_details, container, false);
mImageView = view.findViewById(R.id.picture_iv);
mTextView = view.findViewById(R.id.details_tv);
Bundle bundle = getArguments();
if (bundle != null) {
Bitmap bitmap = getArguments().getParcelable("image");
mImageView.setImageBitmap(bitmap);
String description = getArguments().getString("description");
mTextView.setText(description);
}
return view;
}
}
с макетом вроде:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView
android:id="@+id/picture_iv"
android:layout_width="300dp"
android:layout_height="300dp"
android:transitionName="sharedImageView"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/details_tv"
android:layout_below="@+id/picture_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="28dp"
android:text="Description"/>
</RelativeLayout>
NB! Необходимо одинаковое "sharedImageView"
имя перехода для всех видов карты и фрагментов деталей.
И MainActivity
должен реализовать логику обработки нажатия маркера:
public class MainActivity extends AppCompatActivity {
static final LatLng KYIV = new LatLng(50.450311, 30.523730);
static final LatLng DNIPRO = new LatLng(48.466111, 35.025278);
private GoogleMap mGoogleMap;
private CustomSupportMapFragment mapFragment;
private DetailsFragment detailsFragment;
public class DetailsEnterTransition extends TransitionSet {
public DetailsEnterTransition() {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform());
}
}
public class DetailsExitTransition extends TransitionSet {
public DetailsExitTransition(final CustomSupportMapFragment mapFragment) {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform());
addListener(new TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
if (mapFragment != null) {
mapFragment.showMarker();
mapFragment.setSharedBitmap(null);
}
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// create "map" fragment
mapFragment = new CustomSupportMapFragment();
// create "details" fragment and transitions animations
detailsFragment = new DetailsFragment();
detailsFragment.setSharedElementEnterTransition(new DetailsEnterTransition());
detailsFragment.setSharedElementReturnTransition(new DetailsExitTransition(mapFragment));
// show "map" fragment
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, mapFragment, "map")
.commit();
// get GoogleMap object
mapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_kyiv);
Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, 200, 250, false);
Marker marker = mGoogleMap.addMarker(new MarkerOptions()
.position(KYIV)
.icon(BitmapDescriptorFactory.fromBitmap(resizedBitmap))
.title("Kyiv"));
marker.setTag(resizedBitmap); // save bitmap1 as tag of marker object
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(KYIV));
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_dnipro);
resizedBitmap = Bitmap.createScaledBitmap(bitmap, 200, 250, false);
marker = mGoogleMap.addMarker(new MarkerOptions()
.position(DNIPRO)
.icon(BitmapDescriptorFactory.fromBitmap(resizedBitmap))
.title("Dnipro"));
marker.setTag(resizedBitmap); // save bitmap2 as tag of marker object
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(KYIV));
mGoogleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
// retrieve bitmap for marker
Bitmap sharedBitmap = (Bitmap)marker.getTag();
// determine position of marker and shared element on screen
Projection projection = mGoogleMap.getProjection();
Point viewPosition = projection.toScreenLocation(marker.getPosition());
final float x = viewPosition.x - sharedBitmap.getWidth() / 2.0f;
final float y = viewPosition.y - sharedBitmap.getHeight();
// show shared ImageView and hide marker
mapFragment.setSharedMarker(marker);
mapFragment.setSharedBitmap(sharedBitmap);
mapFragment.setSharedViewInitialPosition(x, y);
mapFragment.getSharedView().setVisibility(View.VISIBLE);
mapFragment.getSharedView().invalidate();
marker.setVisible(false);
// prepare data for "details" fragment
Bundle bundle = new Bundle();
bundle.putParcelable("image", sharedBitmap);
bundle.putString("description", marker.getTitle());
detailsFragment.setArguments(bundle);
// create and start shared element transition animation
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.addSharedElement(mapFragment.getSharedView(), mapFragment.getSharedView().getTransitionName());
ft.replace(R.id.container, detailsFragment, "details");
ft.addToBackStack("details");
ft.commit();
return true; // prevent centring map on marker
}
});
}
});
}
}
Вот и все. Примечание: это не полнофункциональный коммерческий код, просто иллюстрация.