java - 谷歌地图在切换内容可见性时闪烁/闪烁黑色

标签 java android google-maps android-nestedscrollview

我已在两个地方将 map fragment 实现为 :

  1. (主) --> (容器)
    -->( fragment 膨胀) --> --> (容器)
    -->( fragment 膨胀) --> --> (容器)
    --> ( map fragment 膨胀) -->
  2. (主) --> (容器)
    -->( fragment 膨胀) --> (容器)
    --> ( map fragment 膨胀) -->

问题是,在第一种情况下,当我单击 map 标记或单击 map fragment ViewGroup 中的 ImageView 时,我的 map 会闪烁 除了在“消失”和“可见”之间切换图标可见性之外什么也不做。第二种情况工作正常。它给了我一个提示, map 的闪烁是由于其他 View 改变了它们在 NestedScrollView 中的可见性。也许也是因为家长数量太多。

我尝试实现 android:layerType="hardware" 但没有帮助。另外,当可见性在 VISIBLE 和 INVISIBLE 之间切换时,一切正常,但这不是解决方案。

我已经记录了告诉 map 的行为并附加了它here 。在记录上,我单击切换按钮并在“消失”和“可见”之间切换一个小勾号图标。

有什么想法可以解决这个问题吗?

代码

主要 Activity

这是一个抽屉导航 Activity
public class MainActivityC extends AppCompatActivity {

    private AppBarConfiguration mAppBarConfiguration;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_c);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
                .setDrawerLayout(drawer)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main_activity_c, menu);
        return true;
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
                || super.onSupportNavigateUp();
    }
}

fragment 1

该 fragment 包含 ViewPager2
public class GalleryFragment extends Fragment{


    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_gallery, container, false);
    }


    private Context context;
    private ViewPager2 viewPager2;
    private TabLayout tabLayout;


    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        context = getActivity();
        initTab();
    }


    private void initTab() {

        viewPager2 = getView().findViewById(R.id.viewpager2_walks_saved);
        viewPager2.setAdapter(new WalksSavedPagerAdapter(getActivity()));
        viewPager2.setUserInputEnabled(false); // NO SCROLL
        viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                switch (position) {
                    case 0:
                        String text1 = "Walks History";
                        ((MainActivityC) context).getSupportActionBar().setTitle(text1);
                        break;
                    case 1:
                        String text2 = "Walks Statistics";
                        ((MainActivityC) context).getSupportActionBar().setTitle(text2);
                        break;
                }
            }
        });

        tabLayout = getView().findViewById(R.id.tabLayout_walks_statistics);
        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(
                tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {

                switch (position) {
                    case 0:
                        tab.setText("Walks History");
                        break;
                    case 1:
                        tab.setText("Walks Statistics");
                        break;
                }

            }
        }
        );
        tabLayoutMediator.attach();
    }

}

布局:

<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="160dp"
        android:background="?attr/colorPrimary">
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|snap"
            android:elevation="4dp">

            <TextView
                android:id="@+id/drawer_fragment_saved_walks_info"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:text="Saved Walks"
                android:textSize="30sp"
                android:textColor="@color/white"
                android:layout_gravity="center"/>
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_height="0dp"
                android:layout_width="match_parent"
                app:layout_collapseMode="pin" />

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    <!--android:layout_height="?attr/actionBarSize"-->
    </com.google.android.material.appbar.AppBarLayout>


    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <!--  Tab to chose between Saved Walks and Statistics -->
        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabLayout_walks_statistics"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent"
            android:layout_gravity="bottom"
            app:tabIndicatorHeight="3dp"
            app:tabMode="fixed"
            app:tabPaddingBottom="4dp"
            app:tabPaddingTop="4dp" />

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager2_walks_saved"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"/>
    </LinearLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>

fragment 2

该 fragment 显示在ViewPager2中并且有自己的ViewPager2
public class StatisticsFragment extends Fragment {

    private ViewPager2 viewPager2;
    private TabLayout tabLayoutViewPager;
    private StatisticsPagerAdapter statisticsPagerAdapter;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_walks_statistics, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        init();
    }


    private void init(){

        statisticsPagerAdapter = new StatisticsPagerAdapter(getActivity());

        viewPager2 = getView().findViewById(R.id.viewpager2_statistics);
        viewPager2.setAdapter(statisticsPagerAdapter);
        viewPager2.setUserInputEnabled(false); // NO SCROLL


        tabLayoutViewPager = getView().findViewById(R.id.tabLayout_statistics);
        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(
                tabLayoutViewPager, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {

                switch (position) {
                    case 0:
                        tab.setText("Events");
                        break;
                    case 1:
                        tab.setText("Chronology");
                        break;
                    case 2:
                        tab.setText("Heat Map");
                        break;
                }

            }
        }
        );
        tabLayoutMediator.attach();

    }
}

布局:

<androidx.core.widget.NestedScrollView
    android:id="@+id/heatmap_nested_scroll_view"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabLayout_statistics"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:background="@android:color/transparent"
            android:layout_marginTop="8dp"
            app:tabIndicatorHeight="3dp"
            app:tabMode="fixed"
            app:tabPaddingBottom="4dp"
            app:tabPaddingTop="4dp" />

        <View
            android:id="@+id/view"
            android:layout_width="match_parent"
            android:layout_height="2dp"
            android:background="@android:color/darker_gray" />

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager2_statistics"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>


    </LinearLayout>

</androidx.core.widget.NestedScrollView>

带有 GoogleMap 的 fragment 3

该 fragment 显示在 ViewPager2 中并保存闪烁的 map
public class StatisticsHeatmapFragment extends Fragment implements OnMapReadyCallback,
        CompoundButton.OnCheckedChangeListener {

    private Context context;
    private Fragment parentFragment;
    private ToggleButton iconRescale;
    private ImageView iconCheck;

    private MapFragment mapFragment;
    private GoogleMap map;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_statistics_heatmap, container, false);
    }


    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        initiate();
    }

    @SuppressLint("ClickableViewAccessibility") // Due to the touch listener
    private void initiate() {
        context = getActivity();

        // A neat way to find the parent fragment in a child ViewPager fragment
        List<Fragment> fragment = getActivity().getSupportFragmentManager().getFragments();
        for (Fragment f:fragment) {
            if (f instanceof StatisticsFragment){
                parentFragment = f;
            }
        }

        ImageView transparentImageView = (ImageView) getView().findViewById(R.id.heatmap_transparent_image);

        // Tag is automatically given by ViewPager2 like "f" + position, but I have overwritten it.
        // So the StatisticsFragment is "f101". There the NestedScrollView locates.
        final NestedScrollView nestedScrollView = (NestedScrollView)
                getActivity().getSupportFragmentManager().findFragmentByTag("f101").getView();

        // The warning comes up because Android wants to remind you to think about the blind or visually impaired people who may be using your app
        transparentImageView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        // Disallow ScrollView to intercept touch events.
                        nestedScrollView.requestDisallowInterceptTouchEvent(true);
                        // Disable touch on transparent view
                        return false;

                    case MotionEvent.ACTION_UP:
                        // Allow ScrollView to intercept touch events.
                        nestedScrollView.requestDisallowInterceptTouchEvent(false);
                        return true;

                    case MotionEvent.ACTION_MOVE:
                        nestedScrollView.requestDisallowInterceptTouchEvent(true);
                        return false;

                    default:
                        return true;
                }
            }

        });


        mapFragment = (MapFragment) getActivity().getFragmentManager()
                .findFragmentById(R.id.map_statistics);
        mapFragment.getMapAsync(this);
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;
        initToggleButtons();
    }


    private void initToggleButtons() {
        iconCheck = getView().findViewById(R.id.icon_check_heatmap_stats);

        iconRescale = getView().findViewById(R.id.icon_rezoom_heatmap_stats);
        iconRescale.setChecked(true);
        iconRescale.setOnCheckedChangeListener(this);

    }


    /**
     * CheckChange listener for events icon (ToggleButton)
     */
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

        if (buttonView.equals(iconRescale)){

            if (isChecked) {
                DrawableCompat.setTint(
                        DrawableCompat.wrap(iconRescale.getBackground()),
                        ContextCompat.getColor(context, R.color.black));
                iconCheck.setVisibility(View.VISIBLE);
                Toast.makeText(context, "Map scale to the data is ON", Toast.LENGTH_SHORT).show();
            } else {
                DrawableCompat.setTint(
                        DrawableCompat.wrap(iconRescale.getBackground()),
                        ContextCompat.getColor(context, R.color.common_google_signin_btn_text_light));
                iconCheck.setVisibility(View.GONE);
                Toast.makeText(context, "Map scale to the data is OFF", Toast.LENGTH_SHORT).show();
            }

        }

    }
}

布局:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        xmlns:map="http://schemas.android.com/apk/res-auto"
        android:name="com.google.android.gms.maps.MapFragment"
        android:id="@+id/map_statistics"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        map:mapType="normal" />

    <ImageView
        android:id="@+id/heatmap_transparent_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@android:color/transparent" />

    <ImageView
        android:id="@+id/icon_check_heatmap_stats"
        android:layout_width="14dp"
        android:layout_height="14dp"
        android:background="@drawable/ic_baseline_check_24"
        android:backgroundTint="@android:color/holo_red_light"
        android:layout_gravity="end|top"
        android:layout_marginTop="28dp"
        android:layout_marginEnd="69dp"/>

    <ToggleButton
        android:id="@+id/icon_rezoom_heatmap_stats"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="@drawable/ic_baseline_zoom_out_map_24"
        android:backgroundTint="@color/black"
        android:layout_gravity="end|top"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="60dp"
        android:textOn=" "
        android:textOff=" "/>
    
</FrameLayout>

附注使用此代码需要多次单击该图标才能发现问题。

最佳答案

我已经解决了我自己的问题,但是更欢迎其他解决方案。

问题在于 map 的父 map <NestedScrollView>android:fillViewport="true"属性,强制 View 拉伸(stretch)其内容以填充视口(viewport)。

解决方案是将 map 的 View 设置为恒定高度。所以,android:layout_height="match_parent"应更改为android:layout_height="500dp"例如。此外,高度可以根据需要动态设置。

添加

Google map View NestedScrollView可以保留android:layout_height="match_parent" 。然后,要修复 View 的高度(避免闪烁所需的),请在 onCreate 中添加此代码 fragment 或onCreateViewActivityFragment分别是:

view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right,
                         int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    int height = v.getHeight();
                    ViewGroup.LayoutParams params = view.getLayoutParams();
                    params.height = height;
                    view.setLayoutParams(params);
                    view.removeOnLayoutChangeListener(this);
                }
            });

关于java - 谷歌地图在切换内容可见性时闪烁/闪烁黑色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65512793/

相关文章:

java - 关于 Math.atan2 的保证

java - vert.x 的logging.properties 中的含义是什么?

android - 获取youtube android应用版本

java - rxjava2 中的运算符延迟

android - 如何使用地理编码器显示位置?

java - 如何使用 eclipse kepler 和 apache 7 制作并运行 servlet

java - 如何在 Java 枚举中使用 name() 方法

java - 如何在低于 21 的 Android API 中使用 VectorDrawables?

ios - 将 Google map 添加到我的应用程序时出现问题

触摸标记时的Android App map 中心