Подтвердить что ты не робот

Перемещение MapFragment (SurfaceView) вызывает мерцание черного фона

Я пытаюсь реализовать новый API Google Maps Google (v2). Однако, похоже, это не соответствует SlidingMenu. Как вы знаете, реализация MapFragment основана на SurfaceView. Проблема в том, что SurfaceView не любит перемещать его - я имею в виду размещение его в передвижных представлениях:

Когда вы перемещаете его, он оставляет черную дыру в месте, где первоначально располагались ее пиксели. Это выглядит как this.

Эта проблема может быть частично решена путем задания прозрачного фона на SurfaceView или даже размещения над ним прозрачного View. Я просто не могу понять, если только для меня результаты неприемлемы или у меня другая проблема, которая заставляет ее выглядеть так, как она выглядит.

Чтобы посмотреть, как это выглядит, просмотрите ЭТОТ ВИДЕО.

(извините за качество, но проблему можно легко увидеть)

Когда нормальный список (оранжевый экран) отрывается при открытии SlidingMenu, анимация гладкая и приятная. Но как только появится MapFragment, на карте появится какая-то странная проблема с обновлением/мерцанием/синхронизацией.

Протестировано на HTC One S и Samsung Galaxy ACE.


Моя супер-сумасшедшая идея решить ее: каждый раз, когда начинается анимация открытия, сделайте снимок экрана MapFragment (это должно быть возможно с SurfaceView) и заложите его на время анимации, Но я действительно не знаю, как это сделать... Сделать снимок экрана не представляется возможным, но, возможно, кто-то будет вдохновлен этим.

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


UPDATE:

Найдено this.

Похоже, что SurfaceView можно изменить на TextureView, чтобы удалить эти ограничения. Но поскольку MapFragment основан на SurfaceView, я не знаю, можно ли его достичь.

Другое обновление Похоже, что эта проблема была решена на устройствах 4.1+. Они просто использовали TextureView. но в более низких версиях нам все равно придется использовать обходные пути.

4b9b3361

Ответ 1

Разумеется, правильное решение для Google поможет устранить проблему (см. вопрос о выпуске Android Maps V2 4639: http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639).

Однако один из моих коллег предложил просто расширить карту за пределами ее контейнера. Если мы расширим фрагмент карты за пределами видимой области его контейнера, например:

android:layout_marginLeft="-40dp"
android:layout_marginRight="-40dp"

мы можем уменьшить/устранить мерцание. Новые устройства (например, Galaxy Nexus) не показывают мерцания после этого взлома, а более старые устройства (например, LG Optimus V) демонстрируют снижение мерцания. Мы должны расширять поля с обеих сторон, чтобы информационные окна были центрированы, когда они были выбраны.


Обновление: эта проблема была исправлена ​​Google 28 августа, но я предполагаю, что ее все равно нужно перевести в релиз.

Ответ 3

Здесь сумасшедшая идея, не перемещайте MapView; -)

То есть, создайте полную ширину экрана MapView за вашим приложением в FrameLayout. Затем заложите свои взгляды сверху и пропустите отверстие в MapView в том месте, которое вам нужно отобразить. При перемещении вам нужно будет обновить положение карты, чтобы оставаться в синхронизации, чтобы пользователь продолжал видеть один и тот же раздел карты, но это должно обновляться лучше, чем перемещение поверхности.

Ответ 4

Ну, Цитируя Dianne Hackborn (разработчик фреймворка Android)

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

Эта архитектура является частью того, почему вы видите эти мерцания.

Некоторые мерцания иногда появляются из-за двойных буферов: блог по кодированию Android объясняет далее.

Вы также можете попробовать и подклассифицировать SurfaceView, чтобы попытаться рисовать фон по-разному. Я не видел примера этого, который не меняет индекс z на вершину. Отметьте этот пост SOA

В противном случае я рекомендую только получать SurfaceHolder после сфокусированного просмотра (попробуйте сделать временный просмотр до тех пор) и удалив SurfaceView, пока он не находится в фокусе и на экране.

Ответ 5

В моем сценарии у меня был начальный фрагмент, который при нажатии кнопки поменялся во втором фрагменте с помощью MapFragment внутри него. Я заметил, что это мерцание произошло только в первый раз, когда вы поменяли фрагмент - вытащил задний стек, а замена другого фрагмента того же типа не вызвала мерцания.

Таким образом, полагая, что это связано с добавлением начального SurfaceView к окну, я попытался добавить пустой экземпляр SurfaceView к первоначально загруженному фрагменту, позади его основного вида. И бинго, больше не мерцайте при анимации в следующем фрагменте!

Я знаю, что это не самое чистое решение, но оно работает. Google MapFragment (или SupportMapFragment в моем случае) по-прежнему отлично работает, поскольку неиспользуемый SurfaceView находится в предыдущем фрагменте.

Я должен добавить, что я использую API v2.

Обновить @VenomVendor

Я добавляю пустой SurfaceView к первому фрагменту, который будет показан, с индексом 0 - за основным видом. В моем случае фрагмент Home - это предыдущий фрагмент, который содержит фрагмент Google Maps, но не уверен, что это важно:

import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class HomeFragment extends FragmentBase {
private SurfaceView sview;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_home, container, false);

    //this fixes google maps surface view black screen animation issue
    sview = new SurfaceView(getActivity());
    sview.setZOrderOnTop(true);    // necessary
    SurfaceHolder holder = sview.getHolder();
    holder.setFormat(PixelFormat.TRANSPARENT);

    container.addView(sview, 0);
    ...
}

Ответ 6

Снимок экрана с карты невозможен, но, возможно, кто-то вдохновится этим.

Это возможно с снимком интерфейса из GoogleMap. Теперь вы можете отображать снимок карты во время прокрутки страницы. С этим я решил свою проблему с ViewPager, возможно, вы можете изменить код в соответствии с вашим SlidingMenu.

Вот мой код для установки моментального снимка (он в том же фрагменте, что и карта, называемый FragmentMap.java):

public void setSnapshot(int visibility) {
    switch(visibility) {
    case View.GONE:
        if(mapFragment.getView().getVisibility() == View.VISIBLE) {
            getMap().snapshot(new SnapshotReadyCallback() {
                @Override
                public void onSnapshotReady(Bitmap arg0) {
                    iv.setImageBitmap(arg0);
                }
            });
            iv.setVisibility(View.VISIBLE);
            mapFragment.getView().setVisibility(View.GONE);
        }
        break;
    case View.VISIBLE:
        if(mapFragment.getView().getVisibility() == View.GONE) {
            mapFragment.getView().setVisibility(View.VISIBLE);
            iv.setVisibility(View.GONE);
        }
        break;
    }
}

Где "mapFragment" - это мой SupportedMapFragment, а "iv" - это ImageView (сделать его match_parent).

И вот я контролирую свиток:

pager.setOnPageChangeListener(new OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if(position == 0 && positionOffsetPixels > 0 || position == 1 && positionOffsetPixels > 0) {
                ((FragmentMap)adapter.getRegisteredFragment(1)).setSnapshot(View.GONE);
            } else if(position == 1 && positionOffsetPixels == 0) {
                ((FragmentMap)adapter.getRegisteredFragment(1)).setSnapshot(View.VISIBLE);
            }
        }
        @Override
        public void onPageScrollStateChanged(int arg0) {}
        @Override
        public void onPageSelected(int arg0) {}
    });

Мой фрагмент с картой (FragmentMap) находится в позиции 1, поэтому мне нужно управлять прокруткой с позиции 0 до 1 и с позиции 1 на 2 (первое if-предложение). "getRegisteredFragment()" - это функция в моем пользовательском FragmentPagerAdapter, в котором у меня есть SparseArray (фрагмент), называемый зарегистрированными фрагментами.

Итак, всякий раз, когда вы переходите на или с вашей карты, вы всегда видите ее снимок. Это очень хорошо для меня.

Ответ 7

Чтобы предотвратить появление MapView (на самом деле SurfaceView), создающего черные дыры, я добавляю пустой вид с прозрачным цветом фона, чтобы покрыть весь MapView, чтобы он мог предотвратить создание MapView черной дыры. Это может сработать для вашей ситуации.

Ответ 8

У меня такая же проблема с webview и SlidingMenu, и я решил, изменив исходный код SlidingMenu, как объяснил здесь от главного разработчика.

Прокомментируйте аппаратное ускорение в методе manageLayers для SlidingMenu. Это кажется единственным решением, поскольку SurfaceViews не работают.

Ответ 9

Еще одно альтернативное решение - использовать новую функцию GoogleMap.snapshot() и вместо этого использовать скриншот карты; как описано здесь.

Ответ 10

У меня была такая же проблема с черным экраном при прокрутке списка, я использовал фрагмент карты с просмотром списка на одном экране. Я решил эту проблему с использованием магического свойства в xml, где я список говорящего списка, мы должны установить android: scrollingCache = "false" .my проблема исправлена. Попробуйте это свойство, чтобы остановить отставание и мерцание на ваших картах.

Ответ 11

Ребята лучшим решением, которое я нашел, было создание этой карты поддержки. Чудеса

SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().zOrderOnTop(true));

Ответ 12

попробуйте добавить..

getHolder() SetFormat (PixelFormat.TRANSLUCENT).

для вашего конструктора SurfaceView. TextureView также должен работать, но вам потребуется отказаться от поддержки устройств sub api 14.

Ответ 13

Измените FrameLayout на RelativeLayout, если возможно

Ответ 14

У меня была такая же проблема, и я использовал обходной путь, основанный на изменении "Видимости".

private GoogleMap mMap;
private SupportMapFragment mMapFragment;

mMapFragment = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.mapFragment));
mMap = mMapFragment.getMap();

//Change the visibility to 'INVISIBLE' before the animation to go to another fragment.
mMapFragment.getView().setVisibility(View.INVISIBLE);

//Change the visibility to 'VISIBLE' after coming back to the original fragment that has map fragment.
mMapFragment.getView().setVisibility(View.VISIBLE);

Ответ 15

Это сработало для меня... Добавить карту: zOrderOnTop = "true" для вашего фрагмента как это...

<fragment
                android:id="@+id/map"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:name="com.google.android.gms.maps.SupportMapFragment""
                map:zOrderOnTop="true"/>

Не забудьте добавить это в родительский ScrollView

xmlns:map="http://schemas.android.com/apk/res-auto"

Ответ 16

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

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

Итак, чтобы удалить мигание, я просто включил другой MapView в макет моей активности (местоположение в действии не имеет значения). Как только Activity загрузится, я просто установил видимость дополнительного MapView в GONE. Это означает, что все ресурсы, необходимые для вашего MapView, готовы к тому, что вы запускаете любой из своих фрагментов с помощью MapViews без каких-либо задержек, без вспышки и всего счастья.

Это, конечно, обходное решение, а не реальное "решение" основной проблемы, но оно решит побочные эффекты.

Итак, чтобы покрыть код, используемый для полноты:

Случайно (но чисто) помещается в мой макет действия:

<com.google.android.gms.maps.MapView
        android:id="@+id/flash_map"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

Затем в классе активности

private MapView flashMap;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

            // Code omitted

    try {
        MapsInitializer.initialize(this);
    } catch (GooglePlayServicesNotAvailableException e) {
        e.printStackTrace();
    }
    flashMap = (MapView)findViewById(R.id.flash_map);
    flashMap.onCreate(savedInstanceState);
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
        flashMap.onSaveInstanceState(outState);
}

@Override
public void onResume() {
    super.onResume();
    flashMap.onResume();
    flashMap.setVisibility(View.GONE); // Just like it was never there...
}

@Override
public void onPause() {
    flashMap.onPause();
    super.onPause();
}

@Override
public void onDestroy() {
    flashMap.onDestroy();
    super.onDestroy();
}

@Override
public void onLowMemory() {
    super.onLowMemory();
    flashMap.onLowMemory();
}