조각을 사용하는 방법을 배우고 있습니다. Fragment
클래스 상단에 세 개의 인스턴스 가 초기화되어 있습니다. 다음과 같은 활동에 조각을 추가하고 있습니다.
선언 및 초기화 :
Fragment A = new AFragment();
Fragment B = new BFragment();
Fragment C = new CFragment();
교체 / 추가 :
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, A);
ft.addToBackStack(null);
ft.commit();
이 스 니펫이 제대로 작동합니다. 모든 프래그먼트가 액티비티에 첨부되며 아무런 문제없이 백 스택에 저장됩니다.
그래서 시작할 때 A
, C
다음과 B
같은 스택 외모 :
| |
|B|
|C|
|A|
___
그리고 ‘뒤로’버튼을 누르면 B
파괴되고 C
다시 시작됩니다.
그러나 A
두 번째로 조각 을 시작하면 백 스택에서 다시 시작하는 대신 백 스택의 맨 위에 추가됩니다.
| |
|A|
|C|
|A|
___
그러나 나는 A
그 위에있는 모든 조각 을 재개 하고 파괴 하고 싶습니다 (있는 경우). 사실, 나는 기본 백 스택 동작을 좋아합니다.
어떻게하면 되나요?
예상 : ( A
다시 시작하고 상단 조각을 파괴해야 함)
| |
| |
| |
|A|
___
편집 : (AC에서 제안)
이것은 내 시도 코드입니다.
private void selectItem(int position) {
Fragment problemSearch = null, problemStatistics = null;
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
String backStateName = null;
Fragment fragmentName = null;
boolean fragmentPopped = false;
switch (position) {
case 0:
fragmentName = profile;
break;
case 1:
fragmentName = submissionStatistics;
break;
case 2:
fragmentName = solvedProblemLevel;
break;
case 3:
fragmentName = latestSubmissions;
break;
case 4:
fragmentName = CPExercise;
break;
case 5:
Bundle bundle = new Bundle();
bundle.putInt("problem_no", problemNo);
problemSearch = new ProblemWebView();
problemSearch.setArguments(bundle);
fragmentName = problemSearch;
break;
case 6:
fragmentName = rankList;
break;
case 7:
fragmentName = liveSubmissions;
break;
case 8:
Bundle bundles = new Bundle();
bundles.putInt("problem_no", problemNo);
problemStatistics = new ProblemStatistics();
problemStatistics.setArguments(bundles);
fragmentName = problemStatistics;
default:
break;
}
backStateName = fragmentName.getClass().getName();
fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped) {
ft.replace(R.id.content_frame, fragmentName);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
// I am using drawer layout
mDrawerList.setItemChecked(position, true);
setTitle(title[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
내가 시작할 때 문제는, A
다음 B
, 다음을 눌러 ‘돌아 가기’ B
를 제거하고 A
다시 시작됩니다. 다시 ‘뒤로’를 누르면 앱이 종료됩니다. 그러나 그것은 빈 창을 표시하고 그것을 닫으려면 세 번 눌러야합니다.
또한, 나는 시작하면 A
, 다음 B
, 다음 C
, 다음, B
다시 …
예상 :
| |
| |
|B|
|A|
___
실제 :
| |
|B|
|B|
|A|
___
onBackPressed()
사용자 지정으로 재정의해야합니까, 아니면 뭔가 빠졌습니까?
답변
문서를 읽으면 트랜잭션 이름 또는 커밋이 제공 한 ID를 기반으로 백 스택을 팝업하는 방법이 있습니다. 이름을 사용하면 “고유 백 스택 항목”논리를 변경하고 강화할 수있는 숫자를 추적 할 필요가 없으므로 더 쉬울 수 있습니다.
당 하나의 백 스택 항목 만 원 Fragment
하므로 백 상태 이름을 Fragment의 클래스 이름 (via getClass().getName()
)으로 지정하십시오. 그런 다음를 교체 할 때이 방법을 Fragment
사용하십시오 popBackStackImmediate()
. true를 반환하면 백 스택에 Fragment 인스턴스가 있음을 의미합니다. 그렇지 않은 경우 실제로 Fragment replacement 로직을 실행하십시오.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
편집하다
문제는-A를 시작한 다음 B를 시작한 다음 뒤로 버튼을 누르면 B가 제거되고 A가 다시 시작됩니다. 다시 뒤로 버튼을 누르면 앱이 종료됩니다. 그러나 그것은 빈 창을 표시하고 그것을 닫으려면 다시 한 번 눌러야합니다.
이것은 FragmentTransaction
나중에 스택을 팝 할 수 있도록 백 스택에 추가 되기 때문 입니다. onBackPressed()
백 스택에 1 개만 포함 된 경우 이를위한 빠른 수정 은 활동을 재정의 하고 마무리하는 것입니다.Fragment
@Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
finish();
}
else {
super.onBackPressed();
}
}
중복 백 스택 항목과 관련하여 조각이 튀어 나오지 않은 경우 조각을 대체하는 조건문은 원래의 코드 스 니펫 과 명확하게 다릅니다 . 당신이하고있는 일은 백 스택이 터 졌는지 여부에 관계없이 백 스택에 추가하는 것입니다.
이와 같은 것은 원하는 것에 더 가깝습니다.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
String fragmentTag = backStateName;
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped && manager.findFragmentByTag(fragmentTag) == null){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment, fragmentTag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
}
}
동일한 프래그먼트를 선택하고 표시되는 동안 조건부가 약간 변경되어 중복 항목이 발생했습니다.
이행:
replaceFragment()
코드에서와 같이 업데이트 된 메소드를 분리 하지 않는 것이 좋습니다 . 이 방법에는 모든 논리가 포함되어 있으며 부품을 움직이면 문제가 발생할 수 있습니다.
이것은 업데이트 된 replaceFragment()
메소드를 클래스에 복사 한 다음 변경 해야한다는 것을 의미합니다
backStateName = fragmentName.getClass().getName();
fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped) {
ft.replace(R.id.content_frame, fragmentName);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
그래서 그것은 단순히
replaceFragment (fragmentName);
편집 # 2
백 스택이 변경 될 때 드로어를 업데이트하려면 Fragment에서 승인하고 클래스 이름을 비교하는 메소드를 작성하십시오. 일치하는 것이 있으면 제목과 선택을 변경하십시오. 또한 OnBackStackChangedListener
유효한 Fragment가있는 경우 업데이트 메소드를 추가하고 업데이트 메소드를 호출하십시오.
예를 들어, 활동의에서 onCreate()
, 추가
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
Fragment f = getSupportFragmentManager().findFragmentById(R.id.content_frame);
if (f != null){
updateTitleAndDrawer (f);
}
}
});
그리고 다른 방법 :
private void updateTitleAndDrawer (Fragment fragment){
String fragClassName = fragment.getClass().getName();
if (fragClassName.equals(A.class.getName())){
setTitle ("A");
//set selected item position, etc
}
else if (fragClassName.equals(B.class.getName())){
setTitle ("B");
//set selected item position, etc
}
else if (fragClassName.equals(C.class.getName())){
setTitle ("C");
//set selected item position, etc
}
}
이제 백 스택이 변경 될 때마다 제목과 확인 된 위치가 visible을 반영합니다 Fragment
.
답변
이 방법으로 문제를 해결할 수 있다고 생각합니다.
public static void attachFragment ( int fragmentHolderLayoutId, Fragment fragment, Context context, String tag ) {
FragmentManager manager = ( (AppCompatActivity) context ).getSupportFragmentManager ();
FragmentTransaction ft = manager.beginTransaction ();
if (manager.findFragmentByTag ( tag ) == null) { // No fragment in backStack with same tag..
ft.add ( fragmentHolderLayoutId, fragment, tag );
ft.addToBackStack ( tag );
ft.commit ();
}
else {
ft.show ( manager.findFragmentByTag ( tag ) ).commit ();
}
}
이 질문 에 원래 게시 된
답변
1 단계 : 활동 클래스와의 인터페이스 구현
public class AuthenticatedMainActivity extends Activity implements FragmentManager.OnBackStackChangedListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
.............
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().add(R.id.frame_container,fragment, "First").addToBackStack(null).commit();
}
private void switchFragment(Fragment fragment){
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).addToBackStack("Tag").commit();
}
@Override
public void onBackStackChanged() {
FragmentManager fragmentManager = getFragmentManager();
System.out.println("@Class: SummaryUser : onBackStackChanged "
+ fragmentManager.getBackStackEntryCount());
int count = fragmentManager.getBackStackEntryCount();
// when a fragment come from another the status will be zero
if(count == 0){
System.out.println("again loading user data");
// reload the page if user saved the profile data
if(!objPublicDelegate.checkNetworkStatus()){
objPublicDelegate.showAlertDialog("Warning"
, "Please check your internet connection");
}else {
objLoadingDialog.show("Refreshing data...");
mNetworkMaster.runUserSummaryAsync();
}
// IMPORTANT: remove the current fragment from stack to avoid new instance
fragmentManager.removeOnBackStackChangedListener(this);
}// end if
}
}
2 단계 : 다른 조각을 호출 할 때이 메소드를 추가하십시오.
String backStateName = this.getClass().getName();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.addOnBackStackChangedListener(this);
Fragment fragmentGraph = new GraphFragment();
Bundle bundle = new Bundle();
bundle.putString("graphTag", view.getTag().toString());
fragmentGraph.setArguments(bundle);
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragmentGraph)
.addToBackStack(backStateName)
.commit();
답변
나는 이것이이 질문에 대답하기에 상당히 늦다는 것을 알고 있지만,이 문제를 혼자서 해결하고 모든 사람과 공유 할 가치가 있다고 생각했습니다 .`
public void replaceFragment(BaseFragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
final FragmentManager fManager = getSupportFragmentManager();
BaseFragment fragm = (BaseFragment) fManager.findFragmentByTag(fragment.getFragmentTag());
transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
if (fragm == null) { //here fragment is not available in the stack
transaction.replace(R.id.container, fragment, fragment.getFragmentTag());
transaction.addToBackStack(fragment.getFragmentTag());
} else {
//fragment was found in the stack , now we can reuse the fragment
// please do not add in back stack else it will add transaction in back stack
transaction.replace(R.id.container, fragm, fragm.getFragmentTag());
}
transaction.commit();
}
그리고 onBackPressed ()에서
@Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount()>1){
super.onBackPressed();
}else{
finish();
}
}
답변
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if(getFragmentManager().getBackStackEntryCount()==0) {
onResume();
}
}
});
답변
더 쉬운 솔루션은이 줄을 바꿀 것입니다
ft.replace(R.id.content_frame, A);
에 ft.add(R.id.content_frame, A);
그리고 XML 레이아웃 내부에서 사용하십시오
android:background="@color/white"
android:clickable="true"
android:focusable="true"
Clickable
즉, 포인터 장치로 클릭하거나 터치 장치로 탭할 수 있습니다.
Focusable
키보드와 같은 입력 장치에서 포커스를 얻을 수 있음을 의미합니다. 키보드와 같은 입력 장치는 입력 자체를 기반으로 입력 이벤트를 보낼 뷰를 결정할 수 없으므로 포커스가있는 뷰로 보냅니다.