Android, Kotlin: ฉันจะอนุญาตให้เพจเจอร์ดูปัดไปทางซ้ายเมื่อจำเป็นได้อย่างไร

สวัสดีท่านผู้ชมที่รัก

สถานการณ์ของฉัน :

ฉันมีเพจเจอร์ที่อนุญาตให้ผู้ใช้ปัดไปทางซ้ายและขวา ฉันมีหน้าจอ (ส่วนย่อย) ที่ผู้ใช้ต้องการให้ทำให้เสร็จก่อนจึงจะปัดนิ้วได้

แก้ไข 4: วิธีแก้ปัญหา

เนื่องจาก ViewPager2 ทำงานเหมือนกับ RecyclerView ฉันจึงเพิ่ม MutableList ให้กับอะแดปเตอร์ของฉัน:

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

ในตอนเริ่มต้น ในรายการมีเพียงชิ้นส่วนที่แสดงก่อนการล็อค เมื่อเงื่อนไขของฉันเป็นไปตามหรือพอใจ ฉันจะเพิ่มส่วนถัดไปในรายการของอะแดปเตอร์ เพื่อให้พร้อมสำหรับการปัด

ด้านล่างนี้เป็นสิ่งเก่าที่ใช้งานไม่ได้:

สิ่งที่ฉันได้ทำไปแล้ว :

ฉันปรับแต่งวิวเพจเจอร์เพื่อล็อคการปัดเมื่อฉันต้องการล็อค (ดูรหัสของฉัน) แต่มันปิดการใช้งานทั้งสองทิศทาง

ตามหลักการแล้ว ฉันต้องการปิดการใช้งานการปัดจากซ้ายไปขวาเท่านั้น : ฉันต้องการให้ผู้ใช้สามารถปัดกลับ (จากขวาไปซ้าย) ฉันแค่ต้องการปิดการใช้งานการปัดไปข้างหน้า (จากซ้ายไปขวา)

ฉันพยายามใช้ onTouchListener บนเพจเจอร์มุมมองของฉันเพื่อตรวจจับทิศทางการปัด แต่จะใช้งานได้เฉพาะเมื่อ ViewPager ถูกปลดล็อคเท่านั้น

คุณสามารถช่วยฉันได้ไหม ?

แก้ไข 3: ปัญหาใหม่

ฉันได้ลองใช้ viewpager2 แล้ว แต่ตอนนี้ฉันมีปัญหากับเลย์เอาต์ลูก ๆ

เมื่อฉันต้องการแสดงแฟรกเมนต์เป็นส่วนอื่น ฉันจะใช้วิธีการขยายที่ฉันเขียนโดยยึดตามสิ่งนี้: วิธีเพิ่ม-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 ฉันไม่พบมุมมองสำหรับข้อยกเว้นรหัส

ฉันเข้าใจว่าเป็นเพราะฉันใช้ตัวจัดการแฟรกเมนต์แทน ChildSupportFragmentManager ดังนั้นฉันจึงแทนที่ตัวจัดการแฟรกเมนต์ด้วยอันที่ดี แต่ตอนนี้ฉันพบข้อขัดข้องสำหรับ: ยังไม่ได้แนบ Fragment

อีกครั้งคุณช่วยฉันได้ไหม?

ขอบคุณมาก !

รหัส :

 /**
 *   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 แบบดิบไว้ที่ด้านล่างของเค้าโครงกิจกรรมที่มี view pager :

<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 เฉพาะในกรณีที่การปัดจากขวาไปซ้าย

มันยุ่งยากนิดหน่อย ดังนั้นหากคุณมีข้อเสนอแนะใดๆ ...




คำตอบ (2)


ก่อนอื่น ฉันขอแนะนำให้ใช้ ViewPager2 เนื่องจากได้รับการปรับให้เหมาะสมมากขึ้นอย่างมากด้วยการใช้ RecyclerView ซึ่งช่วยให้คุณสามารถลบหน้าได้อย่างสวยงามโดยไม่มีความล่าช้าของเฟรม

อย่างไรก็ตาม ไม่ว่าคุณจะเลือกใช้การติดตั้งแบบใด ฉันจะฟังว่าเพจนั้นเลื่อนไปแล้วหรือไม่ (ทั้งคู่มีอินเทอร์เฟซ onPageChange/โทรกลับที่คุณสามารถเพิ่ม/ลงทะเบียนได้ และเมื่อตำแหน่ง > currPage และ (positionOffset == 0 หรือสถานะการเลื่อน == IDLE) (เพจได้ชำระเรียบร้อยแล้ว) ฉันจะลบเพจก่อนหน้า

แจ้งให้เราทราบหากคุณต้องการตัวอย่าง อย่างไรก็ตาม ทุกอย่างข้างต้นควรเป็นเพียงสิ่งที่คุณต้องทำ

หากคุณต้องการเก็บการใช้งานแบบเก่าของคุณต่อไป ฉันจะบันทึกตำแหน่ง x ปัจจุบันของนิ้วของผู้ใช้ (อย่างถูกต้องด้วย onTouch) และหากน้อยกว่า ให้ตั้งค่า ViewPager2.isUserInputEnabled = false

ViewPager2.isUserInputEnabled = newX >= originalX 

อย่างไรก็ตาม นี่เป็นเรื่องยุ่งยากเนื่องจากผู้ใช้สามารถใช้หลายนิ้วได้ และการใช้งาน onScroll ของ ViewPager จะทริกเกอร์หลังจากที่ผู้ใช้เลื่อนแล้วเท่านั้น ทำให้เกิดข้อผิดพลาดหากคุณปิดใช้งานการเลื่อนแม้หลังจากผ่านไป 1 พิกเซลหลังจากที่ผู้ใช้สัมผัสหน้าจอแล้ว ฉันขอแนะนำให้ลบหน้า

person PenguinDan    schedule 09.05.2020
comment
ขอบคุณสำหรับคำตอบและคำแนะนำของคุณ ฉันไม่รู้เลยว่ามีวิดเจ็ต viewpager2 ความผิดฉันเอง ! ฉันรู้สึกว่าการใช้ Recyclerview ทำให้เกิดความยุ่งยากและอาจจะล่าช้าบ้าง แต่ฉันก็ยังคงต่อสู้กับเพจเจอร์ต่อไป ฉันจะพยายามใช้ทั้งสองอย่างเพื่อความอยากรู้ แต่ตัวเลือกที่ถูกต้องน่าจะเป็น viewpager2 ฉันคิดว่า - person Ch4BRN; 10.05.2020
comment
ฉันแค่หวังว่าฉันจะพบตัวอย่างอย่างรวดเร็วเพื่อทำความเข้าใจวิธีใช้งาน VP2 - person Ch4BRN; 10.05.2020

วิธีแก้ไขคือใช้ physics จาก NeverScrollableScrollPhysics()

person NN73 Player    schedule 09.05.2020
comment
นี่ไม่ใช่แค่ใน Flutter เท่านั้นเหรอ? - person Ch4BRN; 09.05.2020