4

亲爱的观众,你好。

我的情况 :

我有一个查看器,可以让我的用户左右滑动。我有一个屏幕(一个片段),我想在用户滑动之前完成它。

编辑 4:解决方案

由于 ViewPager2 像 RecyclerView 一样工作,我在我的适配器中添加了一个 MutableList:

     var fragmentList = mutableListOf<Fragment>(
            BasicInfoFragment.newInstance(
                activity
            ),
            BondsFragment.newInstance(
                activity
            ),
    ...

一开始,列表中只有“锁定”之前显示的片段。当我的条件得到满足或满足时,我将下一个片段添加到适配器的列表中,以便它们可以刷卡

以下是不起作用的旧东西:

我做了什么 :

我自定义了 viewpager 以在我希望它被锁定时锁定滑动(请参阅我的代码),但它禁用了两个方向。

理想情况下,我只想禁用从左到右的滑动:我希望用户可以向后滑动(从右到左)。我只想禁用向前滑动(从左到右)。

我试图在我的视图寻呼机上实现一个 onTouchListener 来检测滑动方向,但它仅在 ViewPager 解锁时才有效。

你能帮助我吗 ?

编辑3:新问题

我曾尝试实现 viewpager2,但现在我遇到了子布局的问题。

当我需要将一个片段显示到另一个片段中时,我使用我基于此编写的扩展方法: how-to-add-a-fragment-in-kotlin-way

看起来像这样:

    inline fun FragmentManager.doTransaction(func: FragmentTransaction.() -> Unit) {
        Log.d(TAG, "doTransaction")
        val fragmentTransaction = beginTransaction()
        fragmentTransaction.func()
        fragmentTransaction.commit()
    }

    fun AppCompatActivity.replaceFragment(frameId: Int, fragment: Fragment) {
        Log.d(TAG, "replaceFragment")
            supportFragmentManager.doTransaction { replace(frameId, fragment) }
    }

所以我有几个片段有这样的事情:

    companion object : CustomCompanion() {
            @JvmStatic
            override fun newInstance(activity: Activity): IdealsFragment {
                val fragment =
                    IdealsFragment(
                        activity
                    )
                   
                (activity as NewCharacterActivity).replaceFragment(
                    R.id.fragmentIdeals_container_ideals,
                    IdealsRecyclerViewFragment.newInstance(
                        activity
                    )
                )
    
                return fragment
            }
        }

问题是使用 ViewPager2,我得到一个“没有找到 id 的视图”异常。

我明白这是因为我使用了片段管理器而不是 ChildSupportFragmentManager,所以我用好的片段管理器替换了片段管理器,但现在我崩溃了:“片段尚未附加。”。

再说一次,你能帮帮我吗?

非常感谢 !

代码 :

 /**
 *   Class "LockableViewPager" :
 *   Custom viewpager that allows or not to swipe between fragments.
 **/
 class LockableViewPager : ViewPager {
    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)


    companion object {
        private const val TAG = "LockableViewPager"
    }

    /**
     * Is swiping enabled ?
     */
    private var swipeEnabled = true


    /**
     * Intercept all touch screen motion events.
     * Allows to watch events as they are dispatched, and
     * take ownership of the current gesture at any point.
     * 
     * @param event : The motion event being dispatched down the hierarchy.
     * @return Return true to steal motion events from the children and have
     * them dispatched to this ViewGroup through onTouchEvent().
     * The current target will receive an ACTION_CANCEL event, and no further
     * messages will be delivered here.
     */
    override fun onTouchEvent(event: MotionEvent): Boolean {
        return when (swipeEnabled) {
            true -> super.onTouchEvent(event)
            false -> //  Do nothing.
                return false
        }
    }
    

    /**
     * Implement this method to intercept all touch screen motion events.  This
     * allows you to watch events as they are dispatched to your children, and
     * take ownership of the current gesture at any point.
     *
     * @param event : The motion event being dispatched down the hierarchy.
     * @return Return true to steal motion events from the children and have
     * them dispatched to this ViewGroup through onTouchEvent().
     * The current target will receive an ACTION_CANCEL event, and no further
     * messages will be delivered here.
     */
    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        return when (swipeEnabled) {
            true -> super.onInterceptTouchEvent(event)
            false -> swipeEnabled
        }
    }

    /**
     *  Sets the swipeEnabled value to lock or unlock swiping
     */
    fun setSwipeEnabled(swipeEnabled: Boolean) {
        this.swipeEnabled = swipeEnabled
    }    
}

编辑 2:也许解决方案?

我将原始视图放在包含视图寻呼机的活动布局的底部:

<View
    android:id="@+id/touch_layer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true" />

我创建了一个实现 View.OnTouchListener 的抽象类:

abstract class OverlayTouchListener : View.OnTouchListener {
    companion object{
        private const val TAG = "OverlayTouchListener"
    }
}

在我的活动中反序列化覆盖视图:

var touchLayer = this.findViewById<View>(R.id.touch_layer)

将 OverlayTouchListener 添加到 touchLayer :

touchLayer?.setOnTouchListener(object : OverlayTouchListener() {
            /**
             * Called when a touch event is dispatched to a view. This allows listeners to
             * get a chance to respond before the target view.
             *
             * @param v The view the touch event has been dispatched to.
             * @param event The MotionEvent object containing full information about
             * the event.
             * @return True if the listener has consumed the event, false otherwise.
             */
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                Log.d(TAG, "onTouch")
                if(event != null){
                    //  Check the swiping direction and ViewPager.isSwipeEnabled 
                    viewPager?.setSwipeEnabled(true)
                    viewPager?.onTouchEvent(event)
                }

                return true
            }

        })

现在,我只需要检查是否启用了刷卡。如果没有,仅当滑动是从右到左时调用 viewPager.onTouchEvent。

这有点棘手,所以如果您有任何建议......

4

1 回答 1

1

首先,我建议使用 ViewPager2,因为它通过 RecyclerView 实现得到了极大的优化,允许您优雅地删除页面而不会出现帧滞后。

但是,无论您选择哪种实现方式,我都只会听页面是否滚动(它们都有一个 onPageChange 接口/回调,您可以添加/注册,以及当位置 > currPage 和 (positionOffset == 0 或滚动状态 == IDLE)(页面已完全解决),我会删除上一页。

如果您想要一个示例,请告诉我,但是,以上所有内容都应该是您需要做的。

如果您想保留旧的实现,我会捕获用户手指的当前 x 位置(正确使用 onTouch),如果它更少,请设置ViewPager2.isUserInputEnabled = false

ViewPager2.isUserInputEnabled = newX >= originalX 

但是,这很棘手,因为用户可以使用多个手指,并且 ViewPager 的 onScroll 实现仅在用户滚动后触发,如果即使在用户触摸屏幕后 1 个像素后禁用滚动也会产生卡顿,我建议删除页面。

于 2020-05-09T18:10:55.707 回答