55

我正在尝试实现新的 Android Google Maps API (v2)。然而,它似乎并不适合SlidingMenu。您可能知道,MapFragment实现是基于SurfaceView. 问题是SurfaceView不喜欢移动它——我的意思是把它放在可移动的视图中:

当你移动它时,它会在最初放置像素的地方留下一个黑洞。它看起来像这样

这个问题可以通过在其上指定透明背景SurfaceView或什至在其上放置透明来部分解决View。我只是想不出结果是否仅对我来说是不可接受的,或者我有一个不同的问题使它看起来像它的样子。

要查看它的外观,请观看此视频

(对不起质量,但问题很容易看出)

当一个普通的列表视图(橙色屏幕)在打开时被拉开SlidingMenu,动画是流畅和漂亮的。但是一旦MapFragment出现,地图上就会出现一些奇怪的刷新/闪烁/同步问题。

在 HTC One S 和三星 Galaxy ACE 上测试。


我解决这个问题的超级疯狂的想法:每次开始动画开始时,截取MapFragment(使用 SurfaceView 应该可以)并在动画期间将其覆盖。但我真的不知道该怎么做...... 不可能截图地图,但也许有人会从中得到启发。

或者也许以其他方式禁用重绘地图,我不知道。


更新:

找到了这个

看来 SurfaceView 可以更改为 TextureView 以消除这些限制。但是由于MapFragment是基于SurfaceView的,不知道能不能实现。

另一个更新 似乎这个问题已经在设备 4.1+ 上得到解决。他们只是使用了 TextureView。但在较低版本上,我们仍然必须使用变通方法。

4

16 回答 16

14

当然,正确的解决方案是让 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)显示闪烁减少。我们必须扩展两边的边距,以便信息窗口在被选中时居中。


更新:谷歌在 8 月 28 日修复了这个问题,但我猜它仍然需要发布。

于 2013-05-15T00:14:59.010 回答
4

这是一个疯狂的想法,不要移动 MapView ;-)

也就是说,在 FrameLayout 的应用程序后面创建一个 MapView 全屏宽度。然后将您的视图放在顶部,并在您需要显示它的位置打一个洞到 MapView。移动时,您需要更新地图位置以保持同步,以便用户继续看到地图的同一部分,但这应该比移动表面视图更好。

于 2013-01-21T23:05:00.313 回答
4

添加 android:hardwareAccelerated="true"您的清单文件。

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

于 2018-05-16T10:23:05.470 回答
3

好吧,引用 Dianne Hackborn(Android 框架工程师)

表面视图实际上是在您的窗户后面,并且在窗户上打了一个孔供您查看。因此,您可以将东西放在窗口的顶部,但窗口中的任何内容都不会出现在其后面。 原帖

这种架构是您看到这些闪烁的部分原因。

由于双缓冲区,有时会出现一些闪烁:Android 编码博客进一步解释

您还可以尝试将其子类化SurfaceView以尝试以不同方式绘制背景。我还没有看到不会将 z-index 更改为顶部的示例。看看这个 SO 帖子

否则,我建议仅SurfaceHolder在您的视图聚焦后获取(尝试在此之前制作一个临时视图)并删除SurfaceViewwhile not in focus 和屏幕上的。

于 2013-01-28T21:56:50.797 回答
2

在我的场景中,我有一个初始片段,在单击按钮时,它会在第二个片段中交换,其中包含一个 MapFragment。我注意到这种闪烁仅在您第一次交换片段时发生 - 弹出返回堆栈,并在另一个相同类型的片段中交换不会导致闪烁。

因此,考虑到它与将初始 SurfaceView 添加到窗口有关,我尝试将 SurfaceView 的空实例添加到我最初加载的片段中,在它的主视图后面。还有宾果游戏,在下一个片段中制作动画时不再闪烁!

我知道这不是最干净的解决方案,但它有效。Google MapFragment(在我的例子中是 SupportMapFragment)仍然可以正常工作,因为未使用的 SurfaceView 在前一个片段中。

我应该添加我正在使用 v2 API。

更新@VenomVendor

我将空的 SurfaceView 添加到要显示的第一个片段,在索引 0 处 - 在主视图后面。在我的例子中,主页片段是包含谷歌地图片段的前一个片段,不确定这是否重要:

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);
    ...
}
于 2013-07-17T16:55:22.350 回答
2

不可能截取地图的屏幕截图,但也许有人会从中得到启发。

可以使用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)。

因此,每当您滚动到地图或从地图滚动时,您总会看到它的快照。这对我来说非常有效。

于 2013-08-14T11:26:04.963 回答
2

这对我有用...将 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"
于 2016-12-22T21:11:59.213 回答
1

我在 webview 和 SlidingMenu 上遇到了同样的问题,我通过修改 SlidingMenu 源代码来解决,正如主要开发人员在此处解释的那样。

注释掉 SlidingMenu 的 manageLayers 方法中的硬件加速。这似乎是唯一的解决方案,因为 SurfaceViews 不起作用。

于 2013-07-04T12:27:08.973 回答
1

尝试添加..

getHolder().setFormat(PixelFormat.TRANSLUCENT);

到 SurfaceView 的构造函数。TextureView 也应该可以工作,但需要您放弃对 sub api 14 设备的支持。

于 2014-06-24T11:09:55.257 回答
1

为了防止 MapView(它实际上是一个 SurfaceView)产生黑洞,我添加了一个具有透明背景色的空视图来覆盖整个 MapView,这样它就可以防止 MapView 产生黑洞。它可能适用于您的情况。

于 2013-03-07T06:37:12.587 回答
1

另一种替代解决方案是使用新GoogleMap.snapshot()功能,并使用地图截图代替;如此处所述。

于 2013-08-13T15:02:24.420 回答
0

I had same issue of black screen on scrolling of list view, i was using map fragment with list view in same screen i have resolved this issue with use of the magical property in xml where i am talking list view just we have to put android:scrollingCache="false".my issue is fixed try this property to stop lagging and flickering in your maps.

于 2013-04-22T09:54:32.430 回答
0

如果可能,将您的 FrameLayout 更改为 RelativeLayout

于 2014-11-09T20:26:15.670 回答
0

我遇到了同样的问题,并使用了基于更改“可见性”的解决方法。

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);
于 2014-12-04T04:13:15.930 回答
0

伙计们,我发现的最佳解决方案是通过此实例化您的支持图。创造奇迹

SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().zOrderOnTop(true));
于 2014-02-21T13:20:25.737 回答
-1

这是我用来摆脱 ViewPager 中闪烁的一个非常简单的解决方法。我想这对于任何 Fragment 或其他动态添加的 MapView 都适用。

问题似乎并不是 MapView 本身,而是运行 MapView 所需的资源。这些资源仅在您第一次在 Activity 中启动 MapView 时加载,并重新用于每个后续 MapView,正如您所期望的那样。这种资源加载是导致屏幕闪烁的原因。

所以为了消除闪烁,我只是在我的 Activity 的布局中包含了另一个 MapView(在 Activity 中的位置无关紧要)。加载 Activity 后,我只需将额外 MapView 的 Visibility 设置为 GONE。这意味着当您使用 MapViews 启动任何 Fragment 时,您的 MapView 所需的所有资源都已准备就绪,没有延迟,没有闪烁,所有的快乐。

这当然是一种解决方法,而不是潜在问题的真正“解决方案”,但它会解决副作用。

因此,为了掩盖用于完整性的代码:

随机(但干净地)放置在我的活动布局中:

<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();
}
于 2013-01-30T04:42:48.620 回答