Google Map + ViewPager2 刷卡冲突

Posted

技术标签:

【中文标题】Google Map + ViewPager2 刷卡冲突【英文标题】:Google Map + ViewPager2 swiping conflict 【发布时间】:2020-07-16 07:29:49 【问题描述】:

有人处理 ViewPager2 + Fragments + GoogleMap 吗?

我遇到了一个非常有趣的问题,在我的 viewpager 中,我有两个选项卡,每个选项卡都呈现片段。

其中一个片段生成了一张谷歌地图。

当我尝试通过该地图进行操纵时,我得到了 viewpager2 试图左右滑动的效果,这真的很烦人,所以我解决它的方法不是很好。

我通过构造函数将 viewpager 暴露给片段之一,并触发了对 top viewpager 活动的回调。

在那里我用逻辑执行了一个简单的isUserInputEnabled,当地图处于活动状态时禁用滑动。

一旦片段附加此回调寄存器并调用逻辑。

一旦片段分离,这个回调就会调用逻辑来重新启用。

这是一个解决方案,但 imo 并不好。有更好的想法吗?

与视图重叠滑动对我来说似乎是一个错误。

/* top activity that hosts viewpager2 and it's tabs(fragments) */
class ViewTap extends AppCompatActivity
all the good stuff about viewpager2: ViewPager2
fun registerUi()
...TapPagerAdapter(...this)

override fun fireSensitivityResolver(fragment: Fragment, flag: Boolean)
 if(fragment is ViewMapLoader)
  this.mViewPager2.isUserInputEnabled = !flag
 


/* callback defintion fo handling events about Tab Capale thingies */
interface TabCapableIf 
 fun fireSensitivityResolver(fragment: Fragment, flag: Boolean)


/* the adapter for viewpager2 */
class TapPagerAdapter(...private val vt: ViewTap) : FragmentStateAdapter(fm,lc)
override fun createFragment(position: Int): Fragment 
return when(position) 
 ....
  CROWD_FRAGMENT ->  ViewCrowd(vmf, vt) 
 


/* the fragment where the recycler view shows */
class ViewCrowd(...,val vt: ViewTap) : Fragment()
 fun subscribeUi()
   some recycler adapter = ItemViewCrowdsAdapter(...,this)
 


/* the card adapter for the recycler view , when a card is clicked transition to map view */
class ItemViewCrowdsAdapter(...,private val vc: ViewCrowd) : AdapterFragmentRecyclerView(vm) 
 override fun onBindViewHolder(holder: ItemHolder, position: Int)
  ...holder.itemView.setOnClickListener
   ...                    fragmentTransaction.replace(R.id.layout_view_crowd_root, ViewMapLoader(...,vc.vt))
  
 


/* the map loader context that shows the map and handles adjusting the sensitivity so that viewpager2 swipe doesn't overlap with map swipe functionality. otherwise as i try swiping on the map the viewpager2 also swipes. */
class class ViewMapLoader(...,private val vt: ViewTap) : Fragment() 
 private lateinit var mTabCapableIf: TabCapableIf
 override fun onAttach(...)
  this.mTabCapableIf = this.vt
  mTabCapableIf.fireSensitivityResolver(this,true)
 

 override fun onDetach()
  mTabCapableIf.fireSensitivityResolver(this,false)
 

【问题讨论】:

【参考方案1】:

尝试覆盖 MapView 以抑制触摸事件

public class MapViewInScroll extends MapView 
public MapViewInScroll(Context context) 
    super(context);


public MapViewInScroll(Context context, AttributeSet attributeSet) 
    super(context, attributeSet);


public MapViewInScroll(Context context, AttributeSet attributeSet, int i) 
    super(context, attributeSet, i);


public MapViewInScroll(Context context, GoogleMapOptions googleMapOptions) 
    super(context, googleMapOptions);


@Override
public boolean dispatchTouchEvent(MotionEvent ev) 
    getParent().requestDisallowInterceptTouchEvent(true);
    return super.dispatchTouchEvent(ev);

并在您的 xml 布局中使用它而不是原始 MapView

                    <YOUR_PACKAGE.SOME_PATH_TO_VIEW.MapViewInScroll
                    android:id="@+id/map"
                    android:layout_
                    android:layout_ />

【讨论】:

ViewPager2 是否需要成为此处的第一个父级,或者您是否真的需要遍历视图树才能找到 ViewPager2 视图? 嗨@Oleg Bozhko 我的xml布局有问题。我使用片段而不是 MapView 来显示地图,所以很明显,当我把我的课程放在技术上时它可以工作(我可以拦截触摸)但没有显示任何地图。有什么想法吗?【参考方案2】:

如果你想检测到用户在屏幕左边框或右边框附近发起滚动以滑动查看器,你可以将dispatchTouchEvent()代码修改为(Kotlin):

private var intercept = false
private val slideBorder = 0.1 // width of the slide-border in percent of the screen width

override fun dispatchTouchEvent(ev: MotionEvent): Boolean 
    when (ev.action) 
        MotionEvent.ACTION_DOWN -> 
           intercept = ev.x > width * slideBorder && ev.x < width * (1 - slideBorder)
        
        MotionEvent.ACTION_MOVE -> 
            parent.requestDisallowInterceptTouchEvent(intercept)                                
                                                                                               
    
    return super.dispatchTouchEvent(ev)

【讨论】:

【参考方案3】:

我通过在地图上方添加一个哑视图解决了这个问题,如下所示:

<FrameLayout
    android:layout_
    android:layout_>

    <FrameLayout
        android:id="@+id/mapContainer"
        android:layout_
        android:layout_ />

    <FrameLayout
        android:id="@+id/mapShim"
        android:layout_
        android:layout_/>

</FrameLayout>

然后我只是在 shim 上监听触摸事件,将它们转发到地图容器并防止父级使用 requestDisallowInterceptTouchEvent(true) 获得通知:

mapShim.setOnTouchListener  _, event ->
    mapContainer.dispatchTouchEvent(event)
    mapContainer.parent.requestDisallowInterceptTouchEvent(true)
    true

【讨论】:

ViewPager2 是否需要成为此处的第一个父级,或者您是否真的需要遍历视图树才能找到 ViewPager2 视图? 上述布局位于 ViewPager2 片段页面之一内。拦截触摸事件会禁用 ViewPager2 滑动。

以上是关于Google Map + ViewPager2 刷卡冲突的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 中使用 TabLayout 和 ViewPager2

ViewPager2&TabLayout:拓展出一个文本选中放大效果

「技术」Google Map干掉倾斜摄影了?

Pixel因忘记退出Google账号导致刷机无法跳过wifi设置

Google Docs 的格式刷快捷键

移除 ViewPager2 Overscroll 动画