Android-как начать переход общего элемента из растрового изображения маркера?

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


person Soheil    schedule 04.03.2021    source источник


Ответы (1)


Вкратце: используйте setTag()/getTag() методы для сохранения / восстановления растрового изображения в объекте маркера и дополнительные ImageView с этим растровым изображением в качестве общего элемента для переходов между фрагментами карты и деталей:

значок общего маркера

TL; DR;

Если вы используете пользовательские растровые изображения в качестве значка маркеров, вы можете сохранить их в _ 3_ объекты с _ 4_, а затем получить растровое изображение значка маркера в _ 5_. Но растрового изображения недостаточно для переходов общих элементов, потому что необходим объект класса View выполнить это. Итак, вам нужно создать дополнительный View (например, ImageView) и использовать его как общий элемент для переходов между фрагментами карты и деталей.

Как правило, вам следует:

  • При запуске приложения (в MainActivity):
  1. создать фрагмент карты с ImageView для выполнения перехода общего элемента;
  2. создать фрагмент деталей с соответствующимImageView для выполнения перехода общего элемента;
  3. создавать анимацию перехода общих элементов;



  • При создании маркера (во фрагменте карты):
  1. просто сохраните растровое изображение в объекте маркера.



  • Когда пользователь нажимал на маркер,

во фрагменте карты:

  1. в извлечении сохраненного растрового изображения из объекта маркера;
  2. установить для полученного растрового изображения общий ImageView;
  3. измените размер ImageView и переместите его так, чтобы он располагался точно над значком маркера;
  4. скрыть значок маркера и показать ImageView со значком маркера вместо маркера;
  5. поместите битовую карту маркера (и, например, описание) в подробный фрагмент с помощью аргументов;
  6. создать и запустить FragmentTransaction;

подробный фрагмент:

  1. получить битовую карту и описание маркера из аргументов и показать их на соответствующих ImageView и TextView;



  • Когда пользователь закрывает фрагмент сведений (во фрагменте карты),
  1. дождитесь окончания анимации перехода и покажите маркер / скрыть 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
                    }
                });
            }
        });

    }

}

Вот и все. Примечание: это не полнофункциональный коммерческий код, просто иллюстрация.

person Andrii Omelchenko    schedule 07.03.2021