Пользовательский ViewPager, позволяющий дочернему элементу управления GoogleMap прокручивать по горизонтали

Я использую GoogleMap (v2 api) внутри фрагмента внутри ViewPager. Первоначальная проблема, с которой я столкнулась, заключалась в том, что ViewPager захватывал все горизонтальные жесты прокрутки, поэтому карта могла быть перетащена только в том случае, если пользователь начал в вертикальном или диагональном направлении. Все горизонтальные перетаскивания были захвачены ViewPager . Я обнаружил, что решение заключается в создании производного класса ViewPager и переопределении метода canScroll . Перетаскиваемый вид передается этому методу, поэтому вы можете принять решение, основанное на типе View.

В моем случае мой фрагмент – это SupportMapFragment (из пакета com.google.android.gms.maps ), который дает мне объект GoogleMap для взаимодействия. Тем не менее, фактический элемент управления, который я получаю в методе canScroll имеет тип maps.jb Я исправил проблему со следующим кодом внутри моего собственного класса ViewPager. Тем не менее, я не чувствую себя комфортно, проверяя это имя класса, когда я ничего не знаю об этом. Что такое maps.jb? Является ли это динамически созданным классом во время выполнения? Возможно ли изменение типа в будущем обновлении структуры? Учитывая только объект View, существует ли более надежный способ проверки того, что перетаскивание было инициировано элементом управления картой?

 @Override protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if(v.getClass().getName().equals("maps.jb")) { return true; } return super.canScroll(v, checkV, dx, x, y); } 

Является ли это динамически созданным классом во время выполнения?

Вероятно, это результат переименования ProGuard.

Возможно ли изменение типа в будущем обновлении структуры?

AFAIK, да. Я не знаю, что ProGuard гарантирует, что имена будут оставаться неизменными между сборками.

Обратите внимание, что это будет зависеть от проекта библиотеки. Когда вы берете новую версию проекта библиотеки, имя класса может измениться. Но, поскольку это привязано к вашему собственному приложению, в крайнем случае вы можете придерживаться названия игры, и просто нужно исправить это имя, когда вы берете новую версию проекта библиотеки.

При этом я согласен с тем, что сопоставление по имени является нехорошим.

Учитывая только объект View, существует ли более надежный способ проверки того, что перетаскивание было инициировано элементом управления картой?

Ну, так как это не MapView , мы не знаем, что именно представляет maps.jb Мы знаем, что это не MapView , так как он не называется MapView , и Google оставил это имя в одиночку (по- -keep через директивы -keep в конфигурации ProGuard), поэтому мы можем использовать его в наших приложениях.

Вы можете попробовать создать собственный MapFragment с помощью собственного MapView и посмотреть, есть ли у вас MapView вместо maps.jb (который может быть некоторым внутренним подклассом MapView используемым SupportMapFragment ). Если вы MapView фактический MapView , вы можете сделать прямые проверки равенства, чтобы увидеть, является ли переданный объект вашим MapFragment .

Или вы могли видеть, что instanceof говорит, что maps.jb является maps.jb .

Ни один из них не гарантированно надежен с течением времени, так как, по-видимому, Google может изменить такие MapView которые MapView обернут. Тем не менее, я предполагаю, что он скорее будет стабильным, чем сгенерированное имя класса.

maps.jb наследуется от SurfaceView . Следовательно, один из способов canScroll() определения того, должен ли View переданный в canScroll() проверять, является ли (v instanceof SurfaceView) . Это не удается, если Maps V2 сделает что-то еще позже (например, расширяет TextureView на уровне API 11+), или если на ваших страницах ViewPager есть другой SurfaceView (например, VideoView ).

Я указал на проблему, чтобы попытаться получить стабильные средства для добавления этого определения в API карт V2.

Надеюсь, это поможет год спустя … В моем случае я решил эту проблему, проигнорировав объект View. Что вы можете сделать, это уведомить CustomViewPager, чтобы текущая страница содержала карту.

 public class CustomViewPager extends ViewPager { @Override protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if (this.containsMap()) { return true; } return super.canScroll(v, checkV, dx, x, y); } } 

В моем случае containsMap () просто проверьте, соответствует ли текущая страница предопределенному индексу страницы:

 public boolean containsMap(){ return getCurrentItem() == MAP_PAGE; } 

Но это может быть более сложным: добавьте метод setCanScrollIndex (int index, boolean canScroll), чтобы сохранить ссылку на те страницы, которые содержат карту. Вызовите его из своей деятельности, когда это необходимо.

Прежде всего, @Rich благодарит за то, что вы поделились своим решением – это было то, что я искал. У меня есть View Pager с фрагментом, который поддерживает SupportMapfragment как один из его элементов. В моем решении у меня есть собственный файл макета XML, так как мне нужно добавить дополнительные фрагменты к фрагменту. Вот мое решение:

 public class MapFragmentScrollOverrideViewPager extends ViewPager { public MapFragmentScrollOverrideViewPager(Context context) { super(context); } public MapFragmentScrollOverrideViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if(v instanceof MapHoldingRelativeLayout) { return true; } return super.canScroll(v, checkV, dx, x, y); } } public class MapHoldingRelativeLayout extends RelativeLayout { public MapHoldingRelativeLayout(Context context) { super(context); } public MapHoldingRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } public MapHoldingRelativeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } } 

Файл макета фрагмента:

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:id="@+id/switchNearbyOffersButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="XXXX" /> <xxx.view.MapHoldingRelativeLayout android:id="@+id/mapLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/switchNearbyOffersButton" /> </RelativeLayout> 

Сам фрагмент:

 public final class NearbyOffersFragment extends SupportMapFragment { public static NearbyOffersFragment newInstance(String content) { NearbyOffersFragment fragment = new NearbyOffersFragment(); return fragment; } private GoogleMap googleMap; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setUpMapIfNeeded(); } private void setUpMapIfNeeded() { if (googleMap == null) { googleMap = getMap(); if (googleMap != null) { setUpMap(); } } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View rootView = inflater.inflate(R.layout.fragment_nearby_offers, container, false); final View mapFragmentLayout = super.onCreateView(inflater, container, savedInstanceState); MapHoldingRelativeLayout mapLayout = (MapHoldingRelativeLayout) rootView .findViewById(R.id.mapLayout); mapLayout.addView(mapFragmentLayout); return rootView; } @Override public void onResume() { super.onResume(); setUpMapIfNeeded(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } private void setUpMap() { googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); googleMap.getUiSettings().setZoomControlsEnabled(true); googleMap.getUiSettings().setAllGesturesEnabled(true); CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(41.474856, -88.056928)) .zoom(14.5f) .build(); googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); } } 

Поскольку исходный макет SupportMapFragment находится внутри моего настраиваемого RelativeLyout, вы можете использовать оператор instanceof, а не ссылаться непосредственно на класс maps.jb …