ส่วนย่อยมากกว่าปัญหาชิ้นส่วนอื่น


271

เมื่อฉันแสดงแฟรกเมนต์หนึ่งอัน (ซึ่งเต็มหน้าจอพร้อม#77000000พื้นหลัง) เหนือแฟรกเมนต์อื่น (ลองเรียกว่า main) แฟรกเมนต์หลักของฉันยังคงตอบสนองต่อการคลิก (เราสามารถคลิกปุ่มได้แม้ว่าเราจะไม่เห็นก็ตาม)

คำถาม : วิธีป้องกันการคลิกในส่วนแรก (หลัก)

แก้ไข

น่าเสียดายที่ฉันไม่สามารถซ่อนชิ้นส่วนหลักเพราะฉันใช้พื้นหลังโปร่งใสในส่วนที่สอง (ดังนั้นผู้ใช้สามารถเห็นสิ่งที่อยู่ด้านหลัง)


จากสิ่งที่คุณให้เราทำงานด้วยคุณควรลองตั้งค่าVisibilityของคุณmain Fragmentเป็นGONEเมื่อคุณไม่ได้ใช้งาน
adneal

1
โดยไม่เห็นว่าคุณใช้วิธีการ onClicked ของคุณอย่างไรฉันคาดเดาว่าคุณจะคืนค่า "เท็จ" เมื่อคลิก
DeeV

@DeeV onClickวิธีการไม่ส่งคืนอะไรเลย แต่คุณให้ความคิดขอบคุณ (ฉันจะโพสต์คำตอบในไม่ช้า)
Dmitry Zaytsev

1
D'โอ้ คุณถูก. onTouch ส่งคืน ฉันแค่หวังว่าฉันจะเข้าใจว่าเหตุใดเหตุการณ์การสัมผัสจึงล้มเหลว ไม่ควรทำเช่นนั้นหากคุณไม่ได้ออกกิจกรรมสัมผัส
DeeV

@DeeV ดูเหมือนว่ามุมมองของคุณ (เช่นด้านบนของมุมมองอื่น ๆ ) ไม่ได้ดึงดูดเหตุการณ์บน Touch แล้วระบบจะค้นหามุมมองอื่นที่มีพิกัดเดียวกันต่อไป
Dmitry Zaytsev

คำตอบ:


578

ตั้งค่าclickableคุณสมบัติบนมุมมองของแฟรกเมนต์ที่สองเป็นจริง มุมมองจะจับเหตุการณ์เพื่อที่จะไม่ถูกส่งผ่านไปยังส่วนหลัก ดังนั้นหากมุมมองของแฟรกเมนต์ที่สองเป็นเลย์เอาต์นี่จะเป็นรหัส:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true" />

4
สิ่งนี้ใช้ได้สำหรับฉัน ดูเหมือนง่ายกว่าวิธีการแก้ปัญหา @Dmitry Zaitsev มีเหตุผลใดบ้างที่ทำให้สิ่งนี้เป็นความคิดที่ไม่ดี? ฉันไม่สามารถคิดอะไรได้ แต่ฉันแค่อยากจะแน่ใจ
ariets

1
สิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันมีRelativeLayoutชิ้นส่วนด้านในและฉันตั้งค่ามุมมองทั้งหมดของclickeableคุณสมบัติ วิธีการแก้ปัญหาของ @Dmitry แก้ปัญหาของฉัน
4gus71n

3
สิ่งนี้ใช้ได้สำหรับฉัน "คลิกได้" ใน Android ค่อนข้างจะเหมือน iOS '"userInteractionEnabled"
mvds

17
เหตุใด Android จึงให้เงื่อนไขการเข้ารหัสที่รุนแรง?
Lo-Tan

1
ฉันมีปัญหาเดียวกันกับ ViewPager เมื่อฉันเลื่อนไปที่หน้าแรกมันจะผ่านไปยังหน้าที่สองด้วยและโซลูชันนี้ไม่ได้ผลสำหรับฉัน ความคิดใด ๆ
Gokhan Arik

72

การแก้ปัญหาค่อนข้างง่าย ในส่วนที่สองของเรา (ที่ทับส่วนหลักของเรา) เราแค่ต้องจับonTouchเหตุการณ์:

@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstance){
    View root = somehowCreateView();

    /*here is an implementation*/

    root.setOnTouchListener(new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            return true;
        }
    });
    return root;
}

โซลูชันของคุณใช้งานได้ +1 สำหรับสิ่งนั้น แต่คุณสามารถบอกฉันได้ไหมว่าทำไมเราต้องทำสิ่งนี้อย่างชัดเจน
ล่า

@Hunt คุณไม่จำเป็นต้อง นั่นเป็นเพียงวิธีการที่จะทำมันอีก (ดูคำตอบที่ได้รับการยอมรับ)
Dmitry Zaytsev

android: clickable = "true" บนเลย์เอาต์หลัก xml ของแฟรกเมนต์ที่สองของคุณ
Rishabh Srivastava

มีปัญหากับวิธีแก้ปัญหานี้เมื่อคุณเข้าโหมดเปิดใช้งานการเข้าถึงได้ง่ายจะไม่อ่านองค์ประกอบแต่ละรายการแทนที่จะได้รับการโฟกัสไปที่มุมมองรูต
Amit Garg

รุ่น Kotlin: root.setOnTouchListener {_, _ -> true}
Gal Rom

21

เพียงเพิ่มclickable="true"และfocusable="true"เค้าโครงเลย์เอาต์

 <android.support.constraint.ConstraintLayout
      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:clickable="true"
      android:focusable="true">

      <!--Your views-->

 </android.support.constraint.ConstraintLayout>

หากคุณกำลังใช้AndroidXลองสิ่งนี้

 <androidx.constraintlayout.widget.ConstraintLayout
      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:clickable="true"
      android:focusable="true">

          <!--Your views-->

 </androidx.constraintlayout.widget.ConstraintLayout>

นี่แตกต่างจากคำตอบที่ยอมรับหรือไม่? focuseableไม่จำเป็นจริงๆ
Dmitry Zaytsev

2
ฉันคิดว่าfocusable="true"ที่นี่เพียงเพื่อหลีกเลี่ยงการเตือนใน Android Studio
Artem M

9

คุณควรซ่อนชิ้นส่วนแรกเมื่อคุณแสดงชิ้นส่วนที่สองหากวางสองชิ้นในมุมมองคอนเทนเนอร์เดียวกัน

หากคุณต้องการทราบคำถามเพิ่มเติมเกี่ยวกับวิธีการแก้ปัญหาเกี่ยวกับ Fragment คุณสามารถดูห้องสมุดของฉัน: https://github.com/JustKiddingBaby/FragmentRigger

FirstFragment firstfragment;
SecondFragment secondFragment;
FragmentManager fm;
FragmentTransaction ft=fm.beginTransaction();
ft.hide(firstfragment);
ft.show(secondFragment);
ft.commit();

1
นี่ควรเป็นคำตอบที่ถูกต้อง! ขอบคุณชาย ฉันได้แก้ไขคำถามนี้ในโครงการอื่น แต่ฉันลืมไปแล้วว่าฉันจะแก้มันอย่างไรและสุดท้ายฉันก็ได้รับคำตอบจากคุณ ขอบคุณ.
Licat Julius

1
ฉันไม่คิดว่านี่เป็นทางออกที่ถูกต้อง แฟรกเมนต์ / กิจกรรมทำงานในมุมมองสแต็ก คุณจะต้องโทรหา. show อีกครั้งหลังจากที่แฟรกเมนต์ด้านบนแตกออกจากสแต็กซึ่งหมายความว่าแฟรกเมนต์ด้านล่างจะต้องได้รับการแจ้งให้ทราบ มันเพิ่งเพิ่มตรรกะเพิ่มเติมเพื่อรักษา
XY

4

คุณต้องเพิ่ม android:focusable="true"ด้วยandroid:clickable="true"

Clickable หมายความว่าสามารถคลิกได้โดยอุปกรณ์ตัวชี้หรือแตะด้วยอุปกรณ์แบบสัมผัส

Focusableหมายความว่าสามารถรับโฟกัสจากอุปกรณ์ป้อนข้อมูลเช่นแป้นพิมพ์ อุปกรณ์อินพุตเช่นแป้นพิมพ์ไม่สามารถตัดสินใจได้ว่ามุมมองใดที่จะส่งเหตุการณ์อินพุตให้เป็นไปตามสัญญาณอินพุตดังนั้นจึงส่งไปยังมุมมองที่มีโฟกัส


2
และ focusable = "true" เป็นสิ่งจำเป็นเพื่อหลีกเลี่ยงการเตือนใน Android Studio ใหม่
Hossam Hassan

2

มีวิธีแก้ปัญหามากกว่าหนึ่งที่เราบางคนสนับสนุนหัวข้อนี้ แต่ฉันอยากจะพูดถึงวิธีการแก้ปัญหาอื่น ๆ หากคุณไม่อยากใส่การคลิกได้และโฟกัสเท่ากันได้จริงกับ ViewGroup ของทุกเลย์เอาต์ใน XML อย่างฉัน คุณสามารถนำไปวางไว้ที่ฐานของคุณหากคุณมีสิ่งที่ชอบด้านล่าง;

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ) : View? {
        super.onCreateView(inflater, container, savedInstanceState)

        val rootView = inflater.inflate(layout, container, false).apply {
            isClickable = true
            isFocusable = true
        }

        return rootView
    }

คุณสามารถใช้ตัวแปรอินไลน์ แต่ฉันไม่ชอบเพราะเหตุผลของฉัน

ฉันหวังว่าจะช่วยให้คนที่เกลียด XML เลย์เอาต์


1

คำตอบที่ยอมรับได้จะ "ทำงาน" แต่จะทำให้ต้นทุนด้านประสิทธิภาพ (ถอนออก, วัดซ้ำเมื่อเปลี่ยนการวางแนว) เนื่องจากชิ้นส่วนที่อยู่ด้านล่างยังคงถูกดึงออกมา บางทีคุณควรค้นหาชิ้นส่วนด้วยแท็กหรือ ID และตั้งค่าการมองเห็นเป็น GONE หรือมองเห็นได้เมื่อคุณต้องการแสดงอีกครั้ง

ใน Kotlin:

fragmentManager.findFragmentByTag(BottomFragment.TAG).view.visibility = GONE

วิธีนี้เหมาะสำหรับทางเลือกhide()และshow()วิธีการFragmentTransactionเมื่อคุณใช้ภาพเคลื่อนไหว คุณเพียงแค่เรียกมันว่าจากonTransitionStart()และของonTransitionEnd()Transition.TransitionListener


1

Metod 1:

คุณสามารถเพิ่มเค้าโครงทั้งหมดได้

android:clickable="true"
android:focusable="true"
android:background="@color/windowBackground"

Metod 2: (โดยทางโปรแกรม)

ขยายส่วนทั้งหมดจากFragmentBaseฯลฯ จากนั้นเพิ่มรหัสนี้ไปที่FragmentBase

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    getView().setBackgroundColor(getResources().getColor(R.color.windowBackground));
    getView().setClickable(true);
    getView().setFocusable(true);
}

0

สิ่งที่คุณทำได้คือคุณสามารถให้คลิกเปล่าไปยังโครงร่างของชิ้นส่วนก่อนหน้าโดยใช้คุณสมบัติ onClick กับโครงร่างหลักของชิ้นส่วนหลักนั้นและในกิจกรรมที่คุณสามารถสร้างฟังก์ชั่นdoNothing(View view)และไม่เขียนอะไรลงไป สิ่งนี้จะทำเพื่อคุณ


0

ดูเหมือนจะเป็นกรณีสำหรับ DialogFragment มิฉะนั้นด้วย Fragment Manager ให้คอมมิทเพื่อซ่อนและอีกอันจะแสดง ที่ได้ผลสำหรับฉัน


0

การเพิ่มของandroid:clickable="true"ไม่ทำงานสำหรับฉัน โซลูชันนี้ใช้ไม่ได้กับ CoordinatorLayout เมื่อเป็นเลย์เอาต์หลัก นั่นเป็นเหตุผลที่ฉันสร้าง RelativeLayout เป็นเลย์เอาต์หลักเพิ่มandroid:clickable="true"และวาง CoordinatorLayout ใน RelativeLayout นี้


0

ฉันมีหลายแฟรกเมนต์ที่มี xml เดียวกัน
หลังจากใช้เวลาหลายชั่วโมงฉันก็ลบsetPageTransformerและมันก็เริ่มทำงาน

   //  viewpager.setPageTransformer(false, new BackgPageTransformer())

ฉันมีเหตุผลที่ scalling

public class BackgPageTransformer extends BaseTransformer {

    private static final float MIN_SCALE = 0.75f;

    @Override
    protected void onTransform(View view, float position) {
        //view.setScaleX Y
    }

    @Override
    protected boolean isPagingEnabled() {
        return true;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.