web-dev-qa-db-ja.com

MapFragment(SurfaceView)を移動すると、黒い背景がちらつきます

新しいAndroid Google Maps API(v2)を実装しようとしています。ただし、 SlidingMen ではうまくいかないようです。ご存知のように、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を使用しただけです。ただし、下位バージョンでは回避策を使用する必要があります。

53
Michał K

もちろん、Googleが問題を修正するための適切な解決策があります(Android Maps V2 issue 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)はちらつきを低減します。選択されたとき。


更新:この問題は8月28日にGoogleによって修正されましたが、まだリリースに含める必要があると思います。

14
Daniel Schuler

このライブラリを使用できます

https://github.com/NyxDigital/NiceSupportMapFragment/

これは私には問題ありません。

6
Erick Martinez

これはクレイジーなアイデアです。MapViewを移動しないでください;-)

つまり、FrameLayoutでアプリの背後にMapView全画面幅を作成します。次に、ビューを上に置き、MapViewを表示する位置に穴を開けます。移動するときは、マップの位置を更新して同期を維持する必要があります。これにより、ユーザーはマップの同じセクションを見続けることができますが、サーフェスビューを移動するよりも更新する方が適切です。

4
Ryan

まあ、ダイアン・ハックボーンを引用(Androidフレームワークエンジニア)

表面ビューは実際にはウィンドウの後ろにあり、ウィンドウを見るためにウィンドウに穴が開けられています。したがって、ウィンドウの上部に物を置くことができますが、ウィンドウの背後には何も表示されません。 元の投稿

このアーキテクチャは、これらのちらつきを見る理由の一部です。

二重バッファが原因でいくつかのちらつきが発生することがあります: Androidコーディングブログでさらに説明しています

SurfaceViewをサブクラス化して、背景を異なる方法で描画することもできます。 z-indexをトップのインデックスに変更しないこの例を見たことはありません。 チェックアウトSO post

それ以外の場合は、ビューがフォーカスされた後にのみSurfaceHolderを取得し(それまで一時的なビューを作成してください)、フォーカスと画面にないときにSurfaceViewを削除することをお勧めします。

3

マップのスクリーンショットを撮ることはできませんが、誰かがこれに触発されるかもしれません。

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の関数で、「registeredFragments」と呼ばれるSparseArray(Fragment)があります。

そのため、マップにスクロールしたりマップからスクロールしたりするたびに、常にスナップショットが表示されます。これは私にとって非常にうまくいきます。

2
Namenlos

別の代替ソリューションは、新しいGoogleMap.snapshot()関数を使用し、代わりにマップのスクリーンショットを使用することです。 here のように記述します。

1
joecks

私のシナリオでは、最初のフラグメントがあり、ボタンをクリックすると、その中にMapFragmentを持つ2番目のフラグメントが入れ替わりました。このちらつきは最初にフラグメントをスワップするときにのみ発生することに気付きました-バックスタックをポップし、同じタイプの別のフラグメントにスワップしてもフリッカーは発生しませんでした。

そこで、最初のSurfaceViewをウィンドウに追加することと関係があると考えて、SurfaceViewの空のインスタンスを、メインビューの背後にある最初にロードしたフラグメントに追加しようとしました。そして、ビンゴ、次のフラグメントでアニメーション化するときにちらつきがなくなります!

私はそれが最もクリーンなソリューションではないことを知っていますが、うまくいきます。 Google MapFragment(または私の場合はSupportMapFragment)は、未使用のSurfaceViewが前のフラグメントにあるため、引き続き正常に機能します。

V2 APIを使用しています。

更新 @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);
    ...
}
1
Breeno

追加 Android:hardwareAccelerated="true"マニフェストファイル内。

例:<application Android:name=".Sample" Android:hardwareAccelerated="true" />

1
Nagalakshmi

WebViewとSlidingMenuで同じ問題が発生しましたが、SlidingMenuのソースコードを here の説明に従ってメイン開発者が修正することで解決しました。

SlidingMenuのmanageLayersメソッドでハードウェアアクセラレーションをコメントアウトします。 SurfaceViewsが機能しないため、これが唯一の解決策のようです。

1
sourcerebels

MapView(実際はSurfaceView)がブラックホールを作成しないように、MapView全体をカバーする透明な背景色の空のビューを追加して、MapViewがブラックホールを生成しないようにします。あなたの状況でうまくいくかもしれません。

1
Acheese

可能であれば、FrameLayoutをRelativeLayoutに変更します

0
Reza

リストビューのスクロールで黒い画面の同じ問題がありました、同じ画面でリストビューでマップフラグメントを使用していました魔法のプロパティを使用してこの問題を解決しましたin xml私はリストビューを話しているAndroid:scrollingCache = "false"。myの問題が修正されました。このプロパティを試して、マップの遅れやちらつきを止めてください。

0
user1414160

追加してみてください。

getHolder()。setFormat(PixelFormat.TRANSLUCENT);

surfaceViewのコンストラクターに。 TextureViewも動作するはずですが、サブAPI 14デバイスのサポートを終了する必要があります。

0
Lee

私は同じ問題を抱えていて、「可視性」の変更に基づいた回避策を使用しました。

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);
0
kalan

これは私のために働いた...このようにあなたのフラグメントにmap: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"
0
karenms

私が見つけた最良の解決策は、これを介してサポートマップをインスタンス化することでした。驚嘆する

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