ViewPager dengan Google Maps API v2: tampilan hitam misterius


95

Saya telah mengintegrasikan fragmen api v2 google maps baru dalam tampilan pager. Saat menggulir dari fragmen peta, tampilan hitam tumpang tindih dengan fragmen yang berdekatan. Seseorang telah memecahkannya?

Edit: tangkapan layar

masukkan deskripsi gambar di sini

public static class PagerAdapter extends FragmentPagerAdapter{

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {

        Fragment pageFragment;

        switch (position) {
        case 0:
            pageFragment = new TabAFragment();
            break;

        case 1:
            pageFragment = new TabBFragment();
            break;

        case 2:
            pageFragment = SupportMapFragment.newInstance();
            break;

        default:
            pageFragment = null;
            break;
        }

        return pageFragment;
    }
}

Apakah ini terjadi pada lebih dari satu perangkat? Mungkin beberapa baris kode dari ViewPager dan implementasi peta Anda dapat membantu untuk lebih memahami masalah Anda.
Adinia

Ya, terjadi di semua perangkat yang saya coba: samsung, htc, android 4.0, 2.3, dll. Saya telah mengintegrasikan peta di aplikasi saya, dan di aplikasi kecil yang bersih hanya dengan pager dan peta, dengan hasil yang sama.
Pepe

@Pepe, tolong katakan, bagaimana Anda mendapatkan GoogleMapobjek dari ViewPager? Terjebak ini selama berminggu-minggu. Jika Anda tidak mengerti pertanyaan dengan baik, maka cari pertanyaan saya, Anda akan menemukan posting saya. Tolong balas.
azizbekian

Saya ingin menambahkan bahwa saat melakukan suatu screen recordmasalah tampaknya tidak terjadi.
theblang

Jawaban:


115

Saya dapat menghentikan permukaan hitam yang tertinggal setelah transisi dengan menempatkan tampilan lain dengan latar belakang transparan di atas bagian ViewPagerdalam a FrameLayout:

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.view.ViewPager
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </android.support.v4.view.ViewPager>

    <!-- hack to fix ugly black artefact with maps v2 -->
    <FrameLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        android:background="@android:color/transparent" />

</FrameLayout>

1
Bagus! Memang tidak sempurna, karena terkadang saat bergerak pager muncul sebagian dari pandangan hitam. Tapi sekarang tidak ada lagi di layar. Terima kasih! (apakah Anda memiliki penjelasan untuk peretasan ini?)
Pepe

7
Tidak juga. Saya hanya memperhatikan di mana kontrol zoom dan lokasi berada di atas permukaan peta, jejak hitam tidak muncul, jadi saya menempatkan tampilan di atas untuk menutupi seluruh peta dan berhasil. Saya setuju itu tidak sempurna - latar belakang hitam tampaknya menjadi bagian dari jendela
GLSurfaceView

5
Sepertinya itu memperbaiki masalah ViewPager saya. Terima kasih, tapi sepertinya saya memiliki masalah yang sama dengan SlideMenu (menu kiri seperti G + / Yahoo), melakukan hal yang sama .. Adakah pemikiran untuk memperbaiki implementasi SlideMenu?
Chrispix

@Chrispix tidak menganimasikan penampung, gunakan animasi hanya di menu samping, itu telah diperbaiki untuk saya.
meh

1
Saya telah melakukan ini dan solusi terprogram di bawah ini, mereka bekerja saat aplikasi berada di latar depan tetapi ketika aplikasi ditutup dan masih berjalan dan Anda kembali ke sana, peta tetap berada di atas ..
L7ColWinters

43

Memiliki masalah yang sama dengan SlidingMenu dan ViewPager. Saya perhatikan bahwa tombol kontrol di fragmen peta tidak berwarna hitam di artefak yang tertinggal. Saya memecahkan masalah dengan mengganti onCreateView()metodeMapFragment (SupportMapFragment)

@Override
public View onCreateView(LayoutInflater inflater, 
                         ViewGroup view, 
                         Bundle savedInstance) {

    View layout = super.onCreateView(inflater, view, savedInstance);
    FrameLayout frameLayout = new FrameLayout(getActivity());
    frameLayout.setBackgroundColor(
        getResources().getColor(android.R.color.transparent));
    ((ViewGroup) layout).addView(frameLayout,
        new ViewGroup.LayoutParams(
            LayoutParams.FILL_PARENT, 
            LayoutParams.FILL_PARENT
        )
    );
    return layout;
}

Saya menggunakannya untuk SlidingMenu juga. Tapi saya memiliki masalah berkedip-kedip (dengan animasi geser) dan itu tidak bisa diterima, terlihat mengerikan. Apa kamu juga punya? Saya menguji HTC One S. Yang menarik, saya hanya memiliki masalah ini dengan animasi pembukaan dan bukan saat menutup SlidingMenu
Michał K

Tidak ada perbaikan yang berhasil untuk saya. Saya memiliki masalah yang hampir sama dengan Michal K. Menggunakan SlidingMenu dan membuka atau menutup secara perlahan dengan kecepatan terus menerus dan tidak ada masalah. Buka atau tekan kembali untuk menutup jendela dan sepertinya peta sedikit tertinggal meninggalkan ruang kosong sampai slide selesai di mana peta kembali ke posisi semula.
qubz

@qubz: Tentang 'menu geser' cobalah menganimasikan menu, bukan peta. Ini memecahkan masalah bagi saya, jika peta tidak bergerak.
meh

@meh: Peta mungkin bergerak saat saya membuka / menutup SlidingMenu. Yang saya maksud dengan memindahkan adalah CameraUpdate. Saya akan melihat apakah saya dapat menjeda animasi, meskipun ini akan menghalangi UX.
qubz

@Lubos Horacek: Bisakah Anda memposting kode sampel. Saya mendapatkan kesalahan pengecualian penunjuk Null ..
avinash

7

Google merilis perbaikan untuk ini, tetapi hanya untuk 4.1+ (Anda tidak perlu mengunduh versi baru PlayServices, mereka menggunakan bendera sisi server)

Inilah yang saya gunakan untuk melewati masalah - Pastikan Anda tidak menyia-nyiakan siklus CPU apa pun pada perangkat> = 4.1

public class FixMapFragment extends SupportMapFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container, 
                             Bundle savedInstanceState) {

        View view = super.onCreateView(inflater, container, savedInstanceState);

        // Fix for black background on devices < 4.1
        if (android.os.Build.VERSION.SDK_INT < 
            android.os.Build.VERSION_CODES.JELLY_BEAN) {
            setMapTransparent((ViewGroup) view);
        }
        return view;
    }

    private void setMapTransparent(ViewGroup group) {
        int childCount = group.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = group.getChildAt(i);
            if (child instanceof ViewGroup) {
                setMapTransparent((ViewGroup) child);
            } else if (child instanceof SurfaceView) {
                child.setBackgroundColor(0x00000000);
            }
        }
    }
}

Saya kira Anda referensi kelas sebagai berikut: FixMapFragment mapFragment = (FixMapFragment) fragmentManager.findFragmentById(R.id.map);dan di tata letak file: <fragment android:id="@+id/map" android:name="com.example.fragments.FixMapFragment" .... Padahal, peta masih berkedip sejauh yang saya tahu (Android 4.0.4).
JJD

@ JJD saya memiliki tampilan peta yang berkedip, apakah ada cara untuk menyelesaikannya?
Rat-a-tat-a-tat Ratatouille

@ Rat-a-tat-a-tatRatatouille Sejauh yang saya tahu, tidak ada solusi yang dapat diandalkan untuk menghindari tampilan peta yang berkedip-kedip.
JJD

saya tidak tahu apakah yang telah saya lakukan untuk saat ini benar atau tidak tetapi berhasil. saya mengatur visibilitas tampilan peta menjadi tidak terlihat dan kemudian setelah beberapa detik mengatur visibilitas tampilan peta kembali ke terlihat. mengurangi flicker tersebut.
Rat-a-tat-a-tat Ratatouille

6

Solusi saya: manfaatkan antarmuka snapshot baru dari GoogleMap dan tampilkan snapshot peta sambil menggulir halaman.

Berikut adalah kode saya untuk menyetel snapshot (ada di fragmen yang sama dengan peta, disebut 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;
    }
}

Di mana "mapFragment" adalah SupportedMapFragment saya dan "iv" adalah ImageView (buat sesuai dengan match_parent).

Dan di sini saya mengontrol gulungan:

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) {}
    });

Fragmen saya dengan peta (FragmentMap) ada di posisi 1, jadi saya perlu mengontrol scroll dari posisi 0 ke 1 dan dari posisi 1 ke 2 (klausa if pertama). "getRegisteredFragment ()" adalah fungsi dalam FragmentPagerAdapter khusus saya, di mana saya memiliki SparseArray (Fragment) yang disebut "terdaftarFragments".

Jadi, setiap kali Anda menggulir ke atau dari peta Anda, Anda selalu melihat snapshotnya. Ini bekerja dengan sangat baik untuk saya.


Jawaban lain tidak berhasil untuk saya - ini adalah satu-satunya yang berhasil. Terima kasih!
alice_silver_man

4

Saya memiliki masalah layar hitam yang sama saat menggulir tampilan daftar, saya menggunakan fragmen peta dengan tampilan daftar di layar yang sama.Saya telah menyelesaikan masalah ini dengan menggunakan properti magis di xml di mana saya berbicara tampilan daftar hanya kita harus meletakkan android: scrollingCache = "false" . Masalah saya telah diperbaiki coba properti ini untuk menghentikan kelambatan dan kedipan di peta Anda.


2

Anda belum memberikan banyak detail jadi hanya begitu banyak yang bisa saya sarankan. Saya memiliki masalah serupa yaitu layar berkedip-kedip di antara tampilan di pager. Ternyata mapView membengkak saat menukar halaman untuk pertama kalinya.

Untuk memperjelas, saya memiliki 3 halaman di pager saya dan peta saya adalah halaman terakhir.

Untuk mengatasi ini, saya menemukan bahwa mengatur jumlah halaman layar mati menjadi 2 (ini berfungsi dalam kasus di atas) sehingga ketika fragmen saya mulai memuat semua tampilan sekaligus.

Lihat http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit (int)


Terima kasih, tapi tidak berhasil. Masalahnya, bagian layar yang tertutup peta, saat berganti ke fragmen lain, tetap hitam, menutupi tampilan fragmen lain ini.
Pepe

hmmm menarik. Saya akan memikirkan hal ini.
Graham Smith

Saya tidak dapat menemukan setOffscreenPageLimit di halaman itu yang ditautkan ke Anda
mplungjan

0

Ada satu solusi lagi untuk masalah ini. Saya menampilkan MapFragment dalam fragmen lain. MapFragment secara dinamis ditambahkan ke dalam FrameLayout.

Solusinya adalah dengan menggunakan frameLayout.setVisibility (View.Visible) dan frameLayout.setVisibility (View.Gone) pada acara buka dan tutup menu geser. Ini membutuhkan pandangan ekstra untuk ditambahkan. Dan area hitam itu benar-benar hilang.

getSlidingMenu().setOnOpenListener(
        new OnOpenListener() {
            @Override
            public void onOpen() {
                frameLayout.setVisibility(View.GONE);
            }
        });

getSlidingMenu().setOnClosedListener(
        new OnClosedListener() {

            @Override
            public void onClosed() {
                frameLayout.setVisibility(View.VISIBLE);
            }
        });

0

Tidak ada metode di atas yang berhasil untuk saya, bahkan metode lain yang saya temukan di tempat lain. Akhirnya, saya memilih solusi parsial. Saya mendengarkan perubahan halaman melalui onPageChangeListener ViewPager, dan menyembunyikan peta saat halamannya mulai bergulir, dan juga menampilkannya lagi saat berhenti bergulir. Saya juga telah menambahkan Tampilan putih untuk ditampilkan saat menggulir.


Ini dapat diperpanjang lebih lanjut untuk menangkap gambar View saat ini ke bitmap, dan kemudian menampilkannya pada ImageView saat pager sedang bergulir. Dengan begitu, pengguna tidak akan menyadari peretasan di baliknya. Namun, menurut saya komputasi ini agak terlalu mahal karena akan memperlambat respons UI terhadap penggesekan.
azyoot

-2

Cukup salin fragmen peta khusus saya ke proyek Anda. Dan jika Anda memiliki garis hitam dengan ScrollView di bagian atas dan bawah disetel ke ScrollView Anda android: fadingEdge = "none"

public class CustomMapFragment extends SupportMapFragment {
private OnActivityCreatedListener onActivityCreatedListener;

public CustomMapFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup view, Bundle savedInstance) {
    View layout = super.onCreateView(inflater, view, savedInstance);

    FrameLayout frameLayout = new FrameLayout(getActivity());
    frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
    ((ViewGroup) layout).addView(frameLayout,
            new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    return layout;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (getOnActivityCreatedListener() != null)
        getOnActivityCreatedListener().onCreated();
}

public OnActivityCreatedListener getOnActivityCreatedListener() {
    return onActivityCreatedListener;
}

public void setOnActivityCreatedListener(
        OnActivityCreatedListener onActivityCreatedListener) {
    this.onActivityCreatedListener = onActivityCreatedListener;
}

public interface OnActivityCreatedListener {
    void onCreated();
}

}

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.