Programming

Fragments에서 onBackPressed ()를 구현하는 방법은 무엇입니까?

procodes 2020. 2. 20. 23:40
반응형

Fragments에서 onBackPressed ()를 구현하는 방법은 무엇입니까?


onBackPressed()Android 활동에서 구현하는 방식과 비슷한 방식으로 Android Fragment에서 구현할 수 있는 방법이 있습니까?

조각 수명주기에는 없습니다 onBackPressed(). onBackPressed()안드로이드 3.0 프래그먼트 를 오버라이드하는 다른 대안이 있습니까?


이 방법으로 onBackPressedActivity에서 재정의 해결했습니다 . 모든이 FragmentTransaction있습니다 addToBackStack커밋하기 전에 :

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();
        //additional code
    } else {
        getSupportFragmentManager().popBackStack();
    }

}

가장 좋은 해결책은

자바 솔루션

간단한 인터페이스를 만듭니다.

public interface IOnBackPressed {
    /**
     * If you return true the back press will not be taken into account, otherwise the activity will act naturally
     * @return true if your processing has priority if not false
     */
    boolean onBackPressed();
}

그리고 당신의 활동에서

public class MyActivity extends Activity {
    @Override public void onBackPressed() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
       if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
          super.onBackPressed();
       }
    } ...
}

마지막으로 조각에서 :

public class MyFragment extends Fragment implements IOnBackPressed{
   @Override
   public boolean onBackPressed() {
       if (myCondition) {
            //action not popBackStack
            return true; 
        } else {
            return false;
        }
    }
}

코 틀린 솔루션

1-인터페이스 작성

interface IOnBackPressed {
    fun onBackPressed(): Boolean
}

2-활동 준비

class MyActivity : AppCompatActivity() {
    override fun onBackPressed() {
        val fragment =
            this.supportFragmentManager.findFragmentById(R.id.main_container)
        (fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
            super.onBackPressed()
        }
    }
}

3-대상 조각 구현

class MyFragment : Fragment(), IOnBackPressed {
    override fun onBackPressed(): Boolean {
        return if (myCondition) {
            //action not popBackStack
            true
        } else {
            false
        }
    }
}

@HaMMeRed에 따르면 여기에 의사 코드가 어떻게 작동 해야하는지 의사가 있습니다. BaseActivitySlidingMenu lib 예제와 같이 하위 조각이있는 기본 활동이 호출되었다고 가정 해 봅시다. 단계는 다음과 같습니다.

먼저 일반적인 메소드를 갖도록 인터페이스를 구현하는 인터페이스와 클래스를 만들어야합니다.

  1. 수업 인터페이스 만들기 OnBackPressedListener

    public interface OnBackPressedListener {
        public void doBack();
    }
    
  2. 의 기술을 구현하는 수업 만들기 OnBackPressedListener

    public class BaseBackPressedListener implements OnBackPressedListener {
        private final FragmentActivity activity;
    
        public BaseBackPressedListener(FragmentActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public void doBack() {
            activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        }
    }
    
  3. 이제부터 코드 BaseActivity와 그 조각 에 대해 작업하겠습니다.

  4. 수업 상단에 비공개 청취자 만들기 BaseActivity

    protected OnBackPressedListener onBackPressedListener;
    
  5. 리스너를 설정하는 메소드 작성 BaseActivity

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
    
  6. 재정의에서 onBackPressed그런 것을 구현하십시오.

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    
  7. 당신의 조각에 onCreateView당신의 청취자를 추가해야합니다

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        activity = getActivity();
    
        ((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
    
        View view = ... ;
    //stuff with view
    
        return view;
    }
    

Voila, 이제 조각으로 다시 클릭하면 사용자 정의 on back 메소드를 잡아야합니다.


이것은 나를 위해 일했다 : https://stackoverflow.com/a/27145007/3934111

@Override
public void onResume() {
    super.onResume();

    if(getView() == null){
        return;
    }

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
                // handle back button's click listener
                return true;
            }
            return false;
        }
    });
}

그런 종류의 기능을 원한다면 활동에서 기능을 재정의 한 다음 YourBackPressed모든 조각에 인터페이스를 추가 해야합니다.이 단추를 누를 때마다 관련 조각을 호출합니다.

편집 : 이전 답변을 추가하고 싶습니다.

오늘이 작업을 수행하려면 다른 패널이 마스터 / 메인 컨텐츠 패널과 동시에 업데이트 될 것으로 예상되는 경우 브로드 캐스트 또는 주문 된 브로드 캐스트를 사용합니다.

LocalBroadcastManager지원 라이브러리에서이 기능을 사용하면 브로드 캐스트를 전송하고 onBackPressed관심있는 조각을 구독하면됩니다. 나는 메시징이 더 분리 된 구현이고 더 잘 확장 될 것이라고 생각한다. 그래서 그것은 나의 공식적인 구현 권장 사항이 될 것이다. 그냥 사용하는 Intent메시지의 필터로의 조치를. 새로 만든 ACTION_BACK_PRESSED을 보내고 활동에서 보내고 관련 조각에서 듣습니다.


그 중 어느 것도 구현하기 쉽지 않으며 최적의 방식으로 작동하지 않습니다.

프래그먼트에는 작업을 수행 할 메소드 호출 onDetach가 있습니다.

@Override
    public void onDetach() {
        super.onDetach();
        PUT YOUR CODE HERE
    }

이 작업을 수행합니다.


addToBackStack아래와 같이 조각 사이를 전환하는 동안 추가 하십시오.

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

쓰면 addToBackStack(null)자체적으로 처리하지만 태그를 제공하면 수동으로 처리해야합니다.


이 질문과 일부 답변이 5 년이 넘었으므로 솔루션을 공유하겠습니다. 이것은 @oyenigun의 답변에 대한 후속 및 현대화입니다.

업데이트 : 이 기사의 맨 아래에는 Activity가 전혀 포함되지 않는 추상 Fragment 확장을 사용하여 대체 구현을 추가했습니다.이 기능은 다른 백 동작이 필요한 중첩 된 조각과 관련된 더 복잡한 조각 계층 구조를 가진 사람에게 유용합니다.

내가 사용하는 일부 프래그먼트가 작은 정보 뷰와 같이 뒤로 버튼으로 닫고 싶은 더 작은 뷰를 가지고 있기 때문에 이것을 구현해야했지만, 이는 동작을 재정의 해야하는 모든 사람에게 좋습니다 조각 내부의 뒤로 버튼.

먼저 인터페이스를 정의하십시오

public interface Backable {
    boolean onBackPressed();
}

내가 부르는이 인터페이스 Backable(이름 지정 규칙의 sticker입니다) onBackPressed()에는 boolean값을 반환 해야하는 단일 메소드 있습니다. 뒤로 버튼 누름이 뒤로 이벤트를 "흡수"했는지 알아야하기 때문에 부울 값을 적용해야합니다. 리턴 true은 추가 조치가 필요하지 않음을 의미하며, 그렇지 않으면 false기본 뒤로 조치가 여전히 수행되어야한다고 말합니다. 이 인터페이스는 자체 파일 (바람직하게는 별도의 패키지 interfaces) 이어야합니다 . 클래스를 패키지로 분리하는 것이 좋습니다.

둘째, 최고의 조각을 찾으십시오

Fragment백 스택에서 마지막 객체 를 반환하는 메서드를 만들었습니다 . 태그를 사용합니다 ... ID를 사용하는 경우 필요한 사항을 변경하십시오. 탐색 상태 등을 처리하는 유틸리티 클래스 에이 정적 메소드가 있지만 물론 가장 적합한 위치에 배치하십시오. 교화를 위해라는 클래스에 내 것을 넣었습니다 NavUtils.

public static Fragment getCurrentFragment(Activity activity) {
    FragmentManager fragmentManager = activity.getFragmentManager();
    if (fragmentManager.getBackStackEntryCount() > 0) {
        String lastFragmentName = fragmentManager.getBackStackEntryAt(
                fragmentManager.getBackStackEntryCount() - 1).getName();
        return fragmentManager.findFragmentByTag(lastFragmentName);
    }
    return null;
}

백 스택 수가 0보다 큰지 확인하십시오. 그렇지 않으면 ArrayOutOfBoundsException런타임에 발생할 수 있습니다. 0보다 크지 않으면 null을 반환합니다. 나중에 null 값을 확인합니다 ...

셋째, 조각으로 구현

Backable뒤로 단추 동작을 대체해야하는 조각이있는 인터페이스를 구현하십시오 . 구현 방법을 추가하십시오.

public class SomeFragment extends Fragment implements 
        FragmentManager.OnBackStackChangedListener, Backable {

...

    @Override
    public boolean onBackPressed() {

        // Logic here...
        if (backButtonShouldNotGoBack) {
            whateverMethodYouNeed();
            return true;
        }
        return false;
    }

}

에서 onBackPressed()재정의, 당신이 필요로하는 어떤 논리했습니다. 뒤로 버튼 이 백 스택을 팝업 하지 않게 하려면 (기본 동작) 백 이벤트가 흡수되었음을 true로 리턴 하십시오. 그렇지 않으면 false를 반환하십시오.

마지막으로, 활동에서 ...

onBackPressed()메소드를 대체 하고이 로직을 추가하십시오.

@Override
public void onBackPressed() {

    // Get the current fragment using the method from the second step above...
    Fragment currentFragment = NavUtils.getCurrentFragment(this);

    // Determine whether or not this fragment implements Backable
    // Do a null check just to be safe
    if (currentFragment != null && currentFragment instanceof Backable) {

        if (((Backable) currentFragment).onBackPressed()) {
            // If the onBackPressed override in your fragment 
            // did absorb the back event (returned true), return
            return;
        } else {
            // Otherwise, call the super method for the default behavior
            super.onBackPressed();
        }
    }

    // Any other logic needed...
    // call super method to be sure the back button does its thing...
    super.onBackPressed();
}

백 스택에서 현재 조각을 얻은 다음 null 검사를 수행하여 Backable인터페이스를 구현하는지 확인합니다 . 그렇다면 이벤트가 흡수되었는지 판별하십시오. 그렇다면 우리는 끝났고 onBackPressed()돌아올 수 있습니다. 그렇지 않으면, 그것을 정상적인 역 프레스로 취급하고 super 메소드를 호출하십시오.

활동을 포함하지 않는 두 번째 옵션

때때로, 당신은 Activity가 이것을 처리하기를 원하지 않으며, 조각 내에서 직접 처리해야합니다. 그러나 누가 백 프레스 API로 프래그먼트를 가질 수 없다고합니까? 조각을 새로운 클래스로 확장하십시오.

Fragment를 확장하고 View.OnKeyListner인터페이스를 구현하는 추상 클래스를 작성하십시오 .

import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public abstract class BackableFragment extends Fragment implements View.OnKeyListener {

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.setFocusableInTouchMode(true);
        view.requestFocus();
        view.setOnKeyListener(this);
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                onBackButtonPressed();
                return true;
            }
        }

        return false;
    }

    public abstract void onBackButtonPressed();
}

보시다시피, 확장되는 조각 BackableFragmentView.OnKeyListener인터페이스를 사용하여 클릭을 자동으로 캡처합니다 . 표준 논리를 사용하여 onBackButtonPressed()구현 된 onKey()메소드 에서 추상 메소드를 호출하여 뒤로 버튼 누름을 식별하십시오. 뒤로 버튼 이외의 키 클릭을 등록해야하는 경우 조각에서 super재정의 할 때 메서드 를 호출해야합니다 onKey(). 그렇지 않으면 추상화의 동작 재정의 됩니다.

사용하기 쉽고 확장하고 구현하십시오.

public class FragmentChannels extends BackableFragment {

    ...

    @Override
    public void onBackButtonPressed() {
        if (doTheThingRequiringBackButtonOverride) {
            // do the thing
        } else {
            getActivity().onBackPressed();
        }
    }

    ...
}

onBackButtonPressed()수퍼 클래스 메소드는 추상적이므로 일단 확장하면 구현해야합니다 onBackButtonPressed(). void프래그먼트 클래스 내에서 작업을 수행하기 만하면되므로 반환 되며 흡수를 다시 액티비티로 전달할 필요가 없습니다. 뒤로 버튼으로 수행하는 작업에 처리가 필요하지 않은 경우 Activity 메서드를 호출 해야 합니다 onBackPressed(). 그렇지 않으면 뒤로 버튼이 비활성화되고 원하지 않습니다!

주의 사항 보시다시피, 이것은 키 리스너를 프래그먼트의 루트 뷰로 설정하므로 집중해야합니다. 이 클래스를 확장하는 프래그먼트에 포함 된 편집 텍스트 (또는 다른 포커스 스틸 링보기)가 있거나 다른 내부 프래그먼트 또는보기가있는 경우이를 별도로 처리해야합니다. 백 프레스에 초점을 잃기 위해 EditText확장하는 좋은 기사가 있습니다 .

누군가가 이것을 유용하게 사용하기를 바랍니다. 행복한 코딩.


해결책은 간단합니다.

1) 모든 조각이 확장되는 기본 조각 클래스가있는 경우이 코드를 해당 클래스에 추가하십시오. 그렇지 않으면 기본 조각 클래스를 작성하십시오

 /* 
 * called when on back pressed to the current fragment that is returned
 */
 public void onBackPressed()
 {
    // add code in super class when override
 }

2) 활동 클래스에서 다음과 같이 onBackPressed를 대체하십시오.

private BaseFragment _currentFragment;

@Override
public void onBackPressed()
{
      super.onBackPressed();
     _currentFragment.onBackPressed();
}

3) Fragment 클래스에서 원하는 코드를 추가하십시오.

 @Override
 public void onBackPressed()
 {
    setUpTitle();
 }

onBackPressed() 조각이 활동에서 분리됩니다.

@Sterling Diaz의 답변에 따르면 나는 그가 옳다고 생각합니다. 그러나 어떤 상황은 잘못 될 것입니다. (예 : 화면 회전)

isRemoving()목표 달성 여부 감지 할 수 있다고 생각합니다 .

onDetach()또는에 쓸 수 있습니다 onDestroyView(). 일입니다.

@Override
public void onDetach() {
    super.onDetach();
    if(isRemoving()){
        // onBackPressed()
    }
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    if(isRemoving()){
        // onBackPressed()
    }
}

글쎄, 나는 이것을 이렇게했고, 그것은 나를 위해 일한다.

간단한 인터페이스

FragmentOnBackClickInterface.java

public interface FragmentOnBackClickInterface {
    void onClick();
}

구현 예

MyFragment.java

public class MyFragment extends Fragment implements FragmentOnBackClickInterface {

// other stuff

public void onClick() {
       // what you want to call onBackPressed?
}

그런 다음 활동에서 onBackPressed를 재정의하십시오.

    @Override
public void onBackPressed() {
    int count = getSupportFragmentManager().getBackStackEntryCount();
    List<Fragment> frags = getSupportFragmentManager().getFragments();
    Fragment lastFrag = getLastNotNull(frags);
    //nothing else in back stack || nothing in back stack is instance of our interface
    if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
        super.onBackPressed();
    } else {
        ((FragmentOnBackClickInterface) lastFrag).onClick();
    }
}

private Fragment getLastNotNull(List<Fragment> list){
    for (int i= list.size()-1;i>=0;i--){
        Fragment frag = list.get(i);
        if (frag != null){
            return frag;
        }
    }
    return null;
}

아래와 같이 프로젝트에 인터페이스를 추가해야합니다.

public interface OnBackPressed {

     void onBackPressed();
}

그런 다음 조각에이 인터페이스를 구현해야합니다.

public class SampleFragment extends Fragment implements OnBackPressed {

    @Override
    public void onBackPressed() {
        //on Back Pressed
    }

}

그리고 당신은 아래처럼 활동 onBackPressed 이벤트 에서이 onBackPressed 이벤트를 트리거 할 수 있습니다.

public class MainActivity extends AppCompatActivity {
       @Override
        public void onBackPressed() {
                Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
                if (currentFragment instanceof OnBackPressed) {  
                    ((OnBackPressed) currentFragment).onBackPressed();
                }
                super.onBackPressed();
        }
}

EventBus를 사용하는 경우 아마도 훨씬 간단한 솔루션 일 것입니다.

조각에서 :

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    EventBus.getDefault().register(this);
}

@Override
public void onDetach() {
    super.onDetach();
    EventBus.getDefault().unregister(this);
}


// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    getSupportFragmentManager().popBackStack();
}

활동 클래스에서 다음을 정의 할 수 있습니다.

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    super.onBackPressed();
}

@Override
public void onBackPressed() {
    EventBus.getDefault().post(new BackPressedMessage(true));
}

BackPressedMessage.java는 POJO 객체 일뿐입니다.

이것은 매우 깨끗하며 인터페이스 / 구현 번거 로움이 없습니다.


이것은 트릭을 수행하는 작은 코드 일뿐입니다.

 getActivity().onBackPressed();

그것이 누군가를 돕기를 바랍니다 :)


이것은 내 솔루션입니다.

MyActivity.java :

public interface OnBackClickListener {
        boolean onBackClick();
    }

    private OnBackClickListener onBackClickListener;

public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
        this.onBackClickListener = onBackClickListener;
    }

@Override
    public void onBackPressed() {
        if (onBackClickListener != null && onBackClickListener.onBackClick()) {
            return;
        }
        super.onBackPressed();
    }

그리고 단편에서 :

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
    @Override
    public boolean onBackClick() {
        if (condition) {
            return false;
        }

        // some codes

        return true;
    }
});

onDestroyView ()를 사용하는 것은 어떻습니까?

@Override
public void onDestroyView() {
    super.onDestroyView();
}

@Override
public void onResume() {
    super.onResume();

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
                // handle back button
                replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);

                return true;
            }

            return false;
        }
    });
}

뒤로 버튼을 눌렀을 때 활동이 완료되도록 ft.addToBackStack () 메소드를 구현하지 마십시오.

proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

다음 단계를 따르십시오.

조각을 추가하는 동안 항상

fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

그런 다음 주요 활동에서 재정의 onBackPressed()

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    getSupportFragmentManager().popBackStack();
} else {
    finish();
}

앱에서 뒤로 버튼을 처리하려면

Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
    if (f != null) 
        getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()               
}

그게 다야!


매우 짧고 달콤한 답변 :

getActivity().onBackPressed();

내 경우의 전체 시나리오에 대한 설명 :

MainActivity에 FragmentA가 있고 FragmentA에서 FragmentB를 열었습니다 (FragmentB는 FragmentA의 자식 또는 중첩 조각입니다)

 Fragment duedateFrag = new FragmentB();
 FragmentTransaction ft  = getFragmentManager().beginTransaction();
 ft.replace(R.id.container_body, duedateFrag);
 ft.addToBackStack(null);
 ft.commit();

이제 FragmentB에서 FragmentA로 이동하려면 간단히 FragmentB를 넣을 수 있습니다 getActivity().onBackPressed();.


활동 수명주기에서 FragmentActivity 또는 AppCompatActivity를 사용하면 항상 Android 뒤로 버튼이 FragmentManager 트랜잭션을 처리합니다.

백 스택을 처리하기 위해 백 스택 수 또는 태그를 처리 할 필요는 없지만 조각을 추가하거나 교체하는 동안 초점을 유지해야합니다. 뒤로 버튼 케이스를 처리하기 위해 다음 스 니펫을 찾으십시오.

    public void replaceFragment(Fragment fragment) {

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
        }
        transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
    }

여기에서는 내 응용 프로그램의 홈 페이지이므로 홈 조각에 대한 스택을 다시 추가하지 않습니다. addFBackStack을 HomeFragment에 추가하면 응용 프로그램이 acitivity의 모든 frament를 제거하기 위해 대기 한 다음 빈 화면이 표시되므로 다음 조건을 유지합니다.

if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
}

이제 acitvity에서 이전에 추가 된 조각을 볼 수 있으며 HomeFragment에 도달하면 앱이 종료됩니다. 다음 스 니펫을 볼 수도 있습니다.

@Override
public void onBackPressed() {

    if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
        closeDrawer();
    } else {
        super.onBackPressed();
    }
}

에 따르면 AndroidX 릴리스 노트 , androidx.activity 1.0.0-alpha01출시 및 출시되고 ComponentActivity, 기존의 새로운 기본 클래스 FragmentActivityAppCompatActivity. 이 릴리스에는 새로운 기능이 있습니다.

이제 액티비티의 메소드를 재정의 할 필요없이 OnBackPressedCallback비아 addOnBackPressedCallback등록하여 onBackPressed()콜백 을 수신 할 수 있습니다.


역행을 처리하기 위해 활동에 단편을 등록 할 수 있습니다.

interface BackPressRegistrar {
    fun registerHandler(handler: BackPressHandler)
    fun unregisterHandler(handler: BackPressHandler)
}

interface BackPressHandler {
    fun onBackPressed(): Boolean
}

용법:

조각에서 :

private val backPressHandler = object : BackPressHandler {
    override fun onBackPressed(): Boolean {
        showClosingWarning()
        return false
    }
}

override fun onResume() {
    super.onResume()
    (activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}

override fun onStop() {
    (activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
    super.onStop()
}

활동 중 :

class MainActivity : AppCompatActivity(), BackPressRegistrar {


    private var registeredHandler: BackPressHandler? = null
    override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
    override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }

    override fun onBackPressed() {
        if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
    }
}

public class MyActivity extends Activity {

    protected OnBackPressedListener onBackPressedListener;

    public interface OnBackPressedListener {
        void doBack();
    }

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    } 

    @Override
    protected void onDestroy() {
        onBackPressedListener = null;
        super.onDestroy();
    }
}

단편에서 다음을 추가하고 mainactivity의 인터페이스를 구현하는 것을 잊지 마십시오.

public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
         ((MyActivity) getActivity()).setOnBackPressedListener(this);
    }

@Override
public void doBack() {
    //BackPressed in activity will call this;
}

}

최고의 솔루션

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity {
    @Override
    public void onBackPressed() {

        FragmentManager fm = getSupportFragmentManager();
        for (Fragment frag : fm.getFragments()) {
            if (frag == null) {
                super.onBackPressed();
                finish();
                return;
            }
            if (frag.isVisible()) {
                FragmentManager childFm = frag.getChildFragmentManager();
                if (childFm.getFragments() == null) {
                    super.onBackPressed();
                    finish();
                    return;
                }
                if (childFm.getBackStackEntryCount() > 0) {
                    childFm.popBackStack();
                    return;
                }
                else {

                    fm.popBackStack();
                    if (fm.getFragments().size() <= 1) {
                        finish();
                    }
                    return;
                }

            }
        }
    }
}

An Activity A가 있고 B, C 및 D와 같은 3 개의 조각을 만드는 경우에는 간단합니다. 이제 조각 B 또는 C에 있고 onBackPressed매번 조각 D로 이동하려는 경우 onBackPressed()방법을 재정의해야 합니다. 기본 활동 A 및 조각으로 이동하면 기본 활동 A에서 해당 조각을 인식 하는 TAG 또는 해당 조각의 이름 을 전달하십시오 .

나는 당신이 쉽게 이해할 수있는 그 예를 보여주고 있습니다 ....

if (savedInstanceState == null) {

   getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();

}

또는 프래그먼트 B에서 프래그먼트 C로 이동하고 다시 누르면 다음과 같이 프래그먼트 D에오고 싶습니다.

btn.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View view) {

        getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
        ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
    }
});

이제 주요 활동에서 onBackPressed () 메소드를 재정의해야합니다 .... 아래와 같이.

@Override
public void onBackPressed() {
    FragmentManager fragmentManager =getSupportFragmentManager();
    if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
        Fragment fragment = new D_Fragment();
        fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
        getSupportActionBar().setTitle("D fragment ");
    } else {
        super.onBackPressed();
    }
}

나는 다음과 같이 다른 접근법을 사용했다.

  • 오토 이벤트 버스는 활동과 조각 사이의 통신에
  • 호출 프래그먼트가 정의한 래핑 된 커스텀 액션을 포함하는 액티비티의 스택Runnable
  • onBackPressed지배 활동에서 호출, 그것은 가장 최근의 사용자 정의 팝업 다시 조치를하고를 실행합니다 Runnable. 스택에 아무것도 없으면 기본값 super.onBackPressed()이 호출됩니다

이 다른 SO 질문에 대한 답변으로 샘플 코드에 대한 전체 접근 방식이 여기 에 포함 됩니다 .


너무 늦었지만 지난주에 같은 문제가 발생했습니다. 어떤 대답도 도움이되지 않았습니다. 그런 다음 코드를 가지고 놀고 있었고 이미 조각을 추가했기 때문에 이것이 효과가있었습니다.

액티비티 OnPageChangeListener에서ViewPager 사용자가 두 번째 활동에 때를 알 수 있도록. 그가 두 번째 활동에 있으면 true다음과 같이 부울 작성하십시오 .

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager.setCurrentItem(0);
    mViewPager.addOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // TODO Auto-generated method stub
                mSectionsPagerAdapter.instantiateItem(mViewPager, position);
                if(position == 1)
                    inAnalytics = true;
                else if(position == 0)
                    inAnalytics = false;
        }

        @Override
        public void onPageScrolled(int position, float arg1, int arg2) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }
    });

이제 뒤로 버튼을 누를 때마다 부울을 확인하고 현재 항목을 첫 번째 조각으로 설정하십시오.

@Override
public void onBackPressed() {
    if(inAnalytics)
        mViewPager.setCurrentItem(0, true);
    else 
        super.onBackPressed();
}

파편: 메소드를 배치하는 BaseFragment를 작성하십시오.

 public boolean onBackPressed();

활동:

@Override
public void onBackPressed() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            if (!fragment.isVisible()) continue;

            if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
                return;
            }
        }
    }

    super.onBackPressed();
}

당신의 활동은 첨부되고 보이는 조각을 통해 실행되며 각각에 대해 onBackPressed () 그중 하나가 'true'를 반환하면 중단됩니다 (처리되었으므로 더 이상의 조치는 없음).


좋아, 나는 마침내 좋은 해결책을 찾았다.

액티비티 하우징의 onCreate ()에서 프래그먼트는 다음과 같이 백 스택 변경 리스너를 추가합니다.

    fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> f = fragmentManager.getFragments();
            //List<Fragment> f only returns one value
            Fragment frag = f.get(0);
            currentFragment = frag.getClass().getSimpleName();
        }
    });

(또한 fragmenManager를 추가하면 활동에 선언됩니다. 이제 조각을 변경할 때마다 현재 조각 문자열이 현재 조각의 이름이됩니다. 그런 다음 onBackPressed () 활동에서 뒤로 버튼의 작업을 다음과 같이 제어 할 수 있습니다.

    @Override
    public void onBackPressed() {

    switch (currentFragment) {
        case "FragmentOne":
            // your code here
            return;
        case "FragmentTwo":
            // your code here
            return;
        default:
            fragmentManager.popBackStack();
            // default action for any other fragment (return to previous)
    }

}

이 방법이 저에게 효과적임을 확인할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/5448653/how-to-implement-onbackpressed-in-fragments



반응형