보기 호출기 내부의 조각 바꾸기
와 ViewPager
을 사용하여FragmentPagerAdapter
입니다의 첫 에 있는ViewPager
호출기는 두 페이지로 구성되어 있습니다..FirstPagerFragment
.SecondPagerFragment
첫 페이지의 버튼을 클릭합니다.다를 FirstPagerFragment
다음 조각 와 함께.
아래에 제 코드가 있습니다.
public class FragmentPagerActivity extends FragmentActivity {
static final int NUM_ITEMS = 2;
MyAdapter mAdapter;
ViewPager mPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pager);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
/**
* Pager Adapter
*/
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
if(position == 0) {
return FirstPageFragment.newInstance();
} else {
return SecondPageFragment.newInstance();
}
}
}
/**
* Second Page FRAGMENT
*/
public static class SecondPageFragment extends Fragment {
public static SecondPageFragment newInstance() {
SecondPageFragment f = new SecondPageFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
return inflater.inflate(R.layout.second, container, false);
}
}
/**
* FIRST PAGE FRAGMENT
*/
public static class FirstPageFragment extends Fragment {
Button button;
public static FirstPageFragment newInstance() {
FirstPageFragment f = new FirstPageFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
View root = inflater.inflate(R.layout.first, container, false);
button = (Button) root.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(null);
trans.commit();
}
});
return root;
}
/**
* Next Page FRAGMENT in the First Page
*/
public static class NextFragment extends Fragment {
public static NextFragment newInstance() {
NextFragment f = new NextFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
return inflater.inflate(R.layout.next, container, false);
}
}
}
...여기 xml 파일이 있습니다.
fragment_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
</LinearLayout>
first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/first_fragment_root_id"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/button"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="to next"/>
</LinearLayout>
이제 문제는...어떤 ID를 사용해야 합니까?
trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
?
하면.R.id.first_fragment_root_id
기능은 뷰어에서 ..
이 입니다.
은 ㅇ
보시는 것처럼 파편을 교체한 후 첫 번째 사진과 같은 상태를 찾을 것으로 예상합니다.
의 가 없는 또 .ViewPager
그리고.FragmentStatePagerAdapter
, 그리고 그것은 그것과 함께 작동합니다.FragmentPagerAdapter
저자가 사용하는 기본 클래스.
먼저 어떤 ID를 사용해야 하는지에 대한 저자의 질문에 답하는 것으로 시작하고자 합니다. 컨테이너의 ID, 즉 보기 호출기 자체의 ID입니다.하지만 여러분도 아마 알아차렸을 것입니다만, 코드에 그 ID를 사용하면 아무 일도 일어나지 않습니다.그 이유를 설명하겠습니다.
을 입니다.ViewPager
채워주세요.다,notifyDataSetChanged()
어댑터의 기본 클래스에 있습니다.
,ViewPager
용을 합니다.getItemPosition()
어떤 페이지를 파기하고 어떤 페이지를 보관해야 하는지 확인하는 추상적인 방법.됩니다를(를) 합니다.POSITION_UNCHANGED
, 원인은 무엇입니까?ViewPager
모든 현재 페이지를 유지하고 결과적으로 새 페이지를 첨부하지 않습니다.서,는,getItemPosition()
해야 합니다.POSITION_NONE
오래된 것으로 불려질 때, 숨겨진 것으로, 논쟁의 파편으로.
0 0 함을 합니다.FirstPageFragment
아니면NextFragment
입니다를(를) 생성할 때 도 이 입니다.FirstPageFragment
때 됩니다. 프래그먼트 을 처리할 수 이라고 생각합니다.ViewPager
그리고.FragmentManager
.
,FragmentPagerAdapter
위치에서 파생된 이름으로 사용된 프래그먼트를 캐시하므로 0 위치에 프래그먼트가 있으면 클래스가 새로 생성되더라도 대체되지 않습니다.두 것은e를 입니다.remove()
FragmentTransaction
텍스트가 많군요. 여기 당신의 경우에 작동해야 할 코드가 있습니다.
public class MyAdapter extends FragmentPagerAdapter
{
static final int NUM_ITEMS = 2;
private final FragmentManager mFragmentManager;
private Fragment mFragmentAtPos0;
public MyAdapter(FragmentManager fm)
{
super(fm);
mFragmentManager = fm;
}
@Override
public Fragment getItem(int position)
{
if (position == 0)
{
if (mFragmentAtPos0 == null)
{
mFragmentAtPos0 = FirstPageFragment.newInstance(new FirstPageFragmentListener()
{
public void onSwitchToNextFragment()
{
mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();
mFragmentAtPos0 = NextFragment.newInstance();
notifyDataSetChanged();
}
});
}
return mFragmentAtPos0;
}
else
return SecondPageFragment.newInstance();
}
@Override
public int getCount()
{
return NUM_ITEMS;
}
@Override
public int getItemPosition(Object object)
{
if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
}
public interface FirstPageFragmentListener
{
void onSwitchToNextFragment();
}
2012년 11월 13일부로 ViewPager에서 조각을 교체하는 것이 훨씬 쉬워졌습니다.Google은 중첩 프래그먼트를 지원하는 Android 4.2를 출시했으며, 새로운 Android Support Library v11에서도 지원되므로 1.6까지 작동합니다.
getChildFragmentManager를 사용하는 경우를 제외하고는 일반적인 조각 교체 방법과 매우 비슷합니다.사용자가 뒤로 버튼을 클릭하면 중첩된 조각 백스택이 터지지 않는 것을 제외하면 작동하는 것으로 보입니다.연결된 질문의 솔루션에 따라 프래그먼트의 하위 관리자에서 popBackStackImediate()를 수동으로 호출해야 합니다.따라서 ViewPager 활동의 BackPressed()를 재정의해야 합니다. 그러면 ViewPager의 현재 조각을 가져오고 getChildFragmentManager().popBackStackImmediate()를 호출합니다.
현재 표시 중인 프래그먼트를 얻는 것도 약간 까다롭기 때문에 이 더러운 "안드로이드:스위처:VIEWPAGER_ID:INDEX" 솔루션을 사용했지만 이 페이지의 두 번째 솔루션에서 설명한 대로 ViewPager의 모든 프래그먼트를 직접 추적할 수도 있습니다.
다음은 사용자가 행을 클릭할 때 ViewPager에 자세히 표시되고 뒤로 버튼이 작동하는 4개의 목록 보기가 있는 ViewPager에 대한 제 코드입니다.간략화를 위해 관련 코드만 넣으려고 했으니 GitHub에 전체 앱을 업로드하고 싶다면 댓글을 남겨주세요.
홈 액티비티.java
public class HomeActivity extends SherlockFragmentActivity {
FragmentAdapter mAdapter;
ViewPager mPager;
TabPageIndicator mIndicator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mAdapter = new FragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
// This the important bit to make sure the back button works when you're nesting fragments. Very hacky, all it takes is some Google engineer to change that ViewPager view tag to break this in a future Android update.
@Override
public void onBackPressed() {
Fragment fragment = (Fragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":"+mPager.getCurrentItem());
if (fragment != null) // could be null if not instantiated yet
{
if (fragment.getView() != null) {
// Pop the backstack on the ChildManager if there is any. If not, close this activity as normal.
if (!fragment.getChildFragmentManager().popBackStackImmediate()) {
finish();
}
}
}
}
class FragmentAdapter extends FragmentPagerAdapter {
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return ListProductsFragment.newInstance();
case 1:
return ListActiveSubstancesFragment.newInstance();
case 2:
return ListProductFunctionsFragment.newInstance();
case 3:
return ListCropsFragment.newInstance();
default:
return null;
}
}
@Override
public int getCount() {
return 4;
}
}
}
제품 나열Fragment.java
public class ListProductsFragment extends SherlockFragment {
private ListView list;
public static ListProductsFragment newInstance() {
ListProductsFragment f = new ListProductsFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View V = inflater.inflate(R.layout.list, container, false);
list = (ListView)V.findViewById(android.R.id.list);
list.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// This is important bit
Fragment productDetailFragment = FragmentProductDetail.newInstance();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.addToBackStack(null);
transaction.replace(R.id.products_list_linear, productDetailFragment).commit();
}
});
return V;
}
}
도움이 되고 훌륭하다고 생각한 @wize의 답변을 바탕으로 부분적으로 원하는 것을 달성할 수 있었습니다. 그 이유는 기능이 교체되면 첫 번째 Fragment로 돌아가길 원했기 때문입니다.그의 코드를 조금 수정해서 달성했습니다.
다음은 FragmentPagerAdapter입니다.
public static class MyAdapter extends FragmentPagerAdapter {
private final class CalendarPageListener implements
CalendarPageFragmentListener {
public void onSwitchToNextFragment() {
mFragmentManager.beginTransaction().remove(mFragmentAtPos0)
.commit();
if (mFragmentAtPos0 instanceof FirstFragment){
mFragmentAtPos0 = NextFragment.newInstance(listener);
}else{ // Instance of NextFragment
mFragmentAtPos0 = FirstFragment.newInstance(listener);
}
notifyDataSetChanged();
}
}
CalendarPageListener listener = new CalendarPageListener();;
private Fragment mFragmentAtPos0;
private FragmentManager mFragmentManager;
public MyAdapter(FragmentManager fm) {
super(fm);
mFragmentManager = fm;
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public int getItemPosition(Object object) {
if (object instanceof FirstFragment && mFragmentAtPos0 instanceof NextFragment)
return POSITION_NONE;
if (object instanceof NextFragment && mFragmentAtPos0 instanceof FirstFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
@Override
public Fragment getItem(int position) {
if (position == 0)
return Portada.newInstance();
if (position == 1) { // Position where you want to replace fragments
if (mFragmentAtPos0 == null) {
mFragmentAtPos0 = FirstFragment.newInstance(listener);
}
return mFragmentAtPos0;
}
if (position == 2)
return Clasificacion.newInstance();
if (position == 3)
return Informacion.newInstance();
return null;
}
}
public interface CalendarPageFragmentListener {
void onSwitchToNextFragment();
}
만 하면 됩니다.CalendarPageFragmentListener
를 통해 됩니다.newInstance
및 FirstFragment.pageListener.onSwitchToNextFragment()
아니면NextFragment.pageListener.onSwitchToNextFragment()
다음을 위한 솔루션을 구현했습니다.
- 탭 내부의 동적 조각 바꾸기
- 탭별 이력 유지관리
- 방향 변경 작업
이를 위한 방법은 다음과 같습니다.
- notifyDataSetChanged() 메서드를 사용하여 조각 바꾸기 적용
- fragment manager는 백스테이지에만 사용하고 fragment 교체에는 사용하지 않습니다.
- memento pattern(스택)을 이용하여 이력을 유지합니다.
어댑터 코드는 다음과 같습니다.
public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
/** The sherlock fragment activity. */
private final SherlockFragmentActivity mActivity;
/** The action bar. */
private final ActionBar mActionBar;
/** The pager. */
private final ViewPager mPager;
/** The tabs. */
private List<TabInfo> mTabs = new LinkedList<TabInfo>();
/** The total number of tabs. */
private int TOTAL_TABS;
private Map<Integer, Stack<TabInfo>> history = new HashMap<Integer, Stack<TabInfo>>();
/**
* Creates a new instance.
*
* @param activity the activity
* @param pager the pager
*/
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
activity.getSupportFragmentManager();
this.mActivity = activity;
this.mActionBar = activity.getSupportActionBar();
this.mPager = pager;
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
/**
* Adds the tab.
*
* @param image the image
* @param fragmentClass the class
* @param args the arguments
*/
public void addTab(final Drawable image, final Class fragmentClass, final Bundle args) {
final TabInfo tabInfo = new TabInfo(fragmentClass, args);
final ActionBar.Tab tab = mActionBar.newTab();
tab.setTabListener(this);
tab.setTag(tabInfo);
tab.setIcon(image);
mTabs.add(tabInfo);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public Fragment getItem(final int position) {
final TabInfo tabInfo = mTabs.get(position);
return Fragment.instantiate(mActivity, tabInfo.fragmentClass.getName(), tabInfo.args);
}
@Override
public int getItemPosition(final Object object) {
/* Get the current position. */
int position = mActionBar.getSelectedTab().getPosition();
/* The default value. */
int pos = POSITION_NONE;
if (history.get(position).isEmpty()) {
return POSITION_NONE;
}
/* Checks if the object exists in current history. */
for (Stack<TabInfo> stack : history.values()) {
TabInfo c = stack.peek();
if (c.fragmentClass.getName().equals(object.getClass().getName())) {
pos = POSITION_UNCHANGED;
break;
}
}
return pos;
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onTabSelected(final ActionBar.Tab tab, final FragmentTransaction ft) {
TabInfo tabInfo = (TabInfo) tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i).equals(tabInfo)) {
mPager.setCurrentItem(i);
}
}
}
@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
public void replace(final int position, final Class fragmentClass, final Bundle args) {
/* Save the fragment to the history. */
mActivity.getSupportFragmentManager().beginTransaction().addToBackStack(null).commit();
/* Update the tabs. */
updateTabs(new TabInfo(fragmentClass, args), position);
/* Updates the history. */
history.get(position).push(new TabInfo(mTabs.get(position).fragmentClass, mTabs.get(position).args));
notifyDataSetChanged();
}
/**
* Updates the tabs.
*
* @param tabInfo
* the new tab info
* @param position
* the position
*/
private void updateTabs(final TabInfo tabInfo, final int position) {
mTabs.remove(position);
mTabs.add(position, tabInfo);
mActionBar.getTabAt(position).setTag(tabInfo);
}
/**
* Creates the history using the current state.
*/
public void createHistory() {
int position = 0;
TOTAL_TABS = mTabs.size();
for (TabInfo mTab : mTabs) {
if (history.get(position) == null) {
history.put(position, new Stack<TabInfo>());
}
history.get(position).push(new TabInfo(mTab.fragmentClass, mTab.args));
position++;
}
}
/**
* Called on back
*/
public void back() {
int position = mActionBar.getSelectedTab().getPosition();
if (!historyIsEmpty(position)) {
/* In case there is not any other item in the history, then finalize the activity. */
if (isLastItemInHistory(position)) {
mActivity.finish();
}
final TabInfo currentTabInfo = getPrevious(position);
mTabs.clear();
for (int i = 0; i < TOTAL_TABS; i++) {
if (i == position) {
mTabs.add(new TabInfo(currentTabInfo.fragmentClass, currentTabInfo.args));
} else {
TabInfo otherTabInfo = history.get(i).peek();
mTabs.add(new TabInfo(otherTabInfo.fragmentClass, otherTabInfo.args));
}
}
}
mActionBar.selectTab(mActionBar.getTabAt(position));
notifyDataSetChanged();
}
/**
* Returns if the history is empty.
*
* @param position
* the position
* @return the flag if empty
*/
private boolean historyIsEmpty(final int position) {
return history == null || history.isEmpty() || history.get(position).isEmpty();
}
private boolean isLastItemInHistory(final int position) {
return history.get(position).size() == 1;
}
/**
* Returns the previous state by the position provided.
*
* @param position
* the position
* @return the tab info
*/
private TabInfo getPrevious(final int position) {
TabInfo currentTabInfo = history.get(position).pop();
if (!history.get(position).isEmpty()) {
currentTabInfo = history.get(position).peek();
}
return currentTabInfo;
}
/** The tab info class */
private static class TabInfo {
/** The fragment class. */
public Class fragmentClass;
/** The args.*/
public Bundle args;
/**
* Creates a new instance.
*
* @param fragmentClass
* the fragment class
* @param args
* the args
*/
public TabInfo(Class fragmentClass, Bundle args) {
this.fragmentClass = fragmentClass;
this.args = args;
}
@Override
public boolean equals(final Object o) {
return this.fragmentClass.getName().equals(o.getClass().getName());
}
@Override
public int hashCode() {
return fragmentClass.getName() != null ? fragmentClass.getName().hashCode() : 0;
}
@Override
public String toString() {
return "TabInfo{" +
"fragmentClass=" + fragmentClass +
'}';
}
}
처음에 모든 탭을 추가할 때 메소드 createHistory()를 호출하여 초기 히스토리를 생성해야 합니다.
public void createHistory() {
int position = 0;
TOTAL_TABS = mTabs.size();
for (TabInfo mTab : mTabs) {
if (history.get(position) == null) {
history.put(position, new Stack<TabInfo>());
}
history.get(position).push(new TabInfo(mTab.fragmentClass, mTab.args));
position++;
}
}
final int position, final Class fragmentClass, final Bundle args를 호출하는 특정 탭으로 조각을 바꾸기를 원할 때마다 다음과 같이 바꿉니다.
/* Save the fragment to the history. */
mActivity.getSupportFragmentManager().beginTransaction().addToBackStack(null).commit();
/* Update the tabs. */
updateTabs(new TabInfo(fragmentClass, args), position);
/* Updates the history. */
history.get(position).push(new TabInfo(mTabs.get(position).fragmentClass, mTabs.get(position).args));
notifyDataSetChanged();
뒤로 누르면 뒤로() 메서드를 호출해야 합니다.
public void back() {
int position = mActionBar.getSelectedTab().getPosition();
if (!historyIsEmpty(position)) {
/* In case there is not any other item in the history, then finalize the activity. */
if (isLastItemInHistory(position)) {
mActivity.finish();
}
final TabInfo currentTabInfo = getPrevious(position);
mTabs.clear();
for (int i = 0; i < TOTAL_TABS; i++) {
if (i == position) {
mTabs.add(new TabInfo(currentTabInfo.fragmentClass, currentTabInfo.args));
} else {
TabInfo otherTabInfo = history.get(i).peek();
mTabs.add(new TabInfo(otherTabInfo.fragmentClass, otherTabInfo.args));
}
}
}
mActionBar.selectTab(mActionBar.getTabAt(position));
notifyDataSetChanged();
}
이 솔루션은 셜록 액션 바와 스와이프 제스처로 작동합니다.
tl;dr: 호스트 컨텐츠를 교체하고 브라우저에서와 같이 뒤로 이동한 내역을 추적하는 호스트 조각을 사용합니다.
사용 사례가 고정된 탭으로 구성되어 있으므로 솔루션이 잘 작동합니다. ViewPager다의 입니다.HostFragment
할 수 할 수 있습니다 . 조각을 합니다.hostfragment.replaceFragment()
:
public void replaceFragment(Fragment fragment, boolean addToBackstack) {
if (addToBackstack) {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit();
} else {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit();
}
}
레이아웃을 ID 로입니다 로 입니다.R.id.hosted_fragment
방법에 제공된 조각과 함께.
GitHub에 대한 자세한 내용과 완전한 작동 예에 대해서는 이 주제에 대한 나의 튜토리얼을 확인하세요!
제시된 솔루션 중 일부는 문제를 부분적으로 해결하는 데 많은 도움을 주었지만, 일부의 경우 프래그먼트 콘텐츠 대신 예상치 못한 예외와 블랙 페이지 콘텐츠가 생성된 솔루션에는 여전히 한 가지 중요한 점이 누락되어 있습니다.
FragmentPagerAdapter 클래스가 항목 ID를 사용하여 캐시된 조각을 FragmentManager에 저장하고 있습니다.따라서 getItemId(int 포지션) 메서드를 재정의하여 최상위 페이지의 경우 위치, 세부 페이지의 경우 100 + 위치를 반환해야 합니다.그렇지 않으면 이전에 생성된 최상위 프래그먼트가 세부 레벨 프래그먼트 대신 캐시에서 반환됩니다.
또한 여기서는 ViewPager를 사용한 단편 페이지와 RadioGroup을 사용한 탭 버튼으로 탭과 같은 활동을 구현하는 방법에 대한 전체 예시를 공유합니다. 이를 통해 상위 페이지를 상세 페이지로 교체할 수 있고 뒤로 가기 버튼도 지원합니다.이 구현은 한 단계의 백스택(항목 목록 - 항목 세부 정보)만 지원하지만 다단계 백스택 구현은 간단합니다.이 예는 Null Pointer를 던지는 경우를 제외하고는 정상적인 경우에 매우 잘 작동합니다.예를 들어 두 번째 페이지로 전환할 때 첫 번째 페이지의 조각을 변경하고(보이지 않는 경우) 첫 번째 페이지로 돌아갑니다.이 문제를 파악한 후 해결 방법을 게시하겠습니다.
public class TabsActivity extends FragmentActivity {
public static final int PAGE_COUNT = 3;
public static final int FIRST_PAGE = 0;
public static final int SECOND_PAGE = 1;
public static final int THIRD_PAGE = 2;
/**
* Opens a new inferior page at specified tab position and adds the current page into back
* stack.
*/
public void startPage(int position, Fragment content) {
// Replace page adapter fragment at position.
mPagerAdapter.start(position, content);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize basic layout.
this.setContentView(R.layout.tabs_activity);
// Add tab fragments to view pager.
{
// Create fragments adapter.
mPagerAdapter = new PagerAdapter(pager);
ViewPager pager = (ViewPager) super.findViewById(R.id.tabs_view_pager);
pager.setAdapter(mPagerAdapter);
// Update active tab in tab bar when page changes.
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int index, float value, int nextIndex) {
// Not used.
}
@Override
public void onPageSelected(int index) {
RadioGroup tabs_radio_group = (RadioGroup) TabsActivity.this.findViewById(
R.id.tabs_radio_group);
switch (index) {
case 0: {
tabs_radio_group.check(R.id.first_radio_button);
}
break;
case 1: {
tabs_radio_group.check(R.id.second_radio_button);
}
break;
case 2: {
tabs_radio_group.check(R.id.third_radio_button);
}
break;
}
}
@Override
public void onPageScrollStateChanged(int index) {
// Not used.
}
});
}
// Set "tabs" radio group on checked change listener that changes the displayed page.
RadioGroup radio_group = (RadioGroup) this.findViewById(R.id.tabs_radio_group);
radio_group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int id) {
// Get view pager representing tabs.
ViewPager view_pager = (ViewPager) TabsActivity.this.findViewById(R.id.tabs_view_pager);
if (view_pager == null) {
return;
}
// Change the active page.
switch (id) {
case R.id.first_radio_button: {
view_pager.setCurrentItem(FIRST_PAGE);
}
break;
case R.id.second_radio_button: {
view_pager.setCurrentItem(SECOND_PAGE);
}
break;
case R.id.third_radio_button: {
view_pager.setCurrentItem(THIRD_PAGE);
}
break;
}
});
}
}
@Override
public void onBackPressed() {
if (!mPagerAdapter.back()) {
super.onBackPressed();
}
}
/**
* Serves the fragments when paging.
*/
private class PagerAdapter extends FragmentPagerAdapter {
public PagerAdapter(ViewPager container) {
super(TabsActivity.this.getSupportFragmentManager());
mContainer = container;
mFragmentManager = TabsActivity.this.getSupportFragmentManager();
// Prepare "empty" list of fragments.
mFragments = new ArrayList<Fragment>(){};
mBackFragments = new ArrayList<Fragment>(){};
for (int i = 0; i < PAGE_COUNT; i++) {
mFragments.add(null);
mBackFragments.add(null);
}
}
/**
* Replaces the view pager fragment at specified position.
*/
public void replace(int position, Fragment fragment) {
// Get currently active fragment.
Fragment old_fragment = mFragments.get(position);
if (old_fragment == null) {
return;
}
// Replace the fragment using transaction and in underlaying array list.
// NOTE .addToBackStack(null) doesn't work
this.startUpdate(mContainer);
mFragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.remove(old_fragment).add(mContainer.getId(), fragment)
.commit();
mFragments.set(position, fragment);
this.notifyDataSetChanged();
this.finishUpdate(mContainer);
}
/**
* Replaces the fragment at specified position and stores the current fragment to back stack
* so it can be restored by #back().
*/
public void start(int position, Fragment fragment) {
// Remember current fragment.
mBackFragments.set(position, mFragments.get(position));
// Replace the displayed fragment.
this.replace(position, fragment);
}
/**
* Replaces the current fragment by fragment stored in back stack. Does nothing and returns
* false if no fragment is back-stacked.
*/
public boolean back() {
int position = mContainer.getCurrentItem();
Fragment fragment = mBackFragments.get(position);
if (fragment == null) {
// Nothing to go back.
return false;
}
// Restore the remembered fragment and remove it from back fragments.
this.replace(position, fragment);
mBackFragments.set(position, null);
return true;
}
/**
* Returns fragment of a page at specified position.
*/
@Override
public Fragment getItem(int position) {
// If fragment not yet initialized, create its instance.
if (mFragments.get(position) == null) {
switch (position) {
case FIRST_PAGE: {
mFragments.set(FIRST_PAGE, new DefaultFirstFragment());
}
break;
case SECOND_PAGE: {
mFragments.set(SECOND_PAGE, new DefaultSecondFragment());
}
break;
case THIRD_PAGE: {
mFragments.set(THIRD_PAGE, new DefaultThirdFragment());
}
break;
}
}
// Return fragment instance at requested position.
return mFragments.get(position);
}
/**
* Custom item ID resolution. Needed for proper page fragment caching.
* @see FragmentPagerAdapter#getItemId(int).
*/
@Override
public long getItemId(int position) {
// Fragments from second level page hierarchy have their ID raised above 100. This is
// important to FragmentPagerAdapter because it is caching fragments to FragmentManager with
// this item ID key.
Fragment item = mFragments.get(position);
if (item != null) {
if ((item instanceof NewFirstFragment) || (item instanceof NewSecondFragment) ||
(item instanceof NewThirdFragment)) {
return 100 + position;
}
}
return position;
}
/**
* Returns number of pages.
*/
@Override
public int getCount() {
return mFragments.size();
}
@Override
public int getItemPosition(Object object)
{
int position = POSITION_UNCHANGED;
if ((object instanceof DefaultFirstFragment) || (object instanceof NewFirstFragment)) {
if (object.getClass() != mFragments.get(FIRST_PAGE).getClass()) {
position = POSITION_NONE;
}
}
if ((object instanceof DefaultSecondragment) || (object instanceof NewSecondFragment)) {
if (object.getClass() != mFragments.get(SECOND_PAGE).getClass()) {
position = POSITION_NONE;
}
}
if ((object instanceof DefaultThirdFragment) || (object instanceof NewThirdFragment)) {
if (object.getClass() != mFragments.get(THIRD_PAGE).getClass()) {
position = POSITION_NONE;
}
}
return position;
}
private ViewPager mContainer;
private FragmentManager mFragmentManager;
/**
* List of page fragments.
*/
private List<Fragment> mFragments;
/**
* List of page fragments to return to in onBack();
*/
private List<Fragment> mBackFragments;
}
/**
* Tab fragments adapter.
*/
private PagerAdapter mPagerAdapter;
}
인덱스 2와 3에 대해 3개의 요소와 2개의 하위 요소로 ViewPager를 만들었습니다. 그리고 여기에 제가 하고 싶었던 것이 있습니다.
StackOverFlow의 이전 질문과 답변의 도움을 받아 이를 구현했으며 여기 링크가 있습니다.
a 내부의 조각을 교체하려면 다음과 같이 하십시오.ViewPager
다의 할 수 .ViewPager
,PagerAdapter
그리고.FragmentStatePagerAdapter
클래스를 프로젝트에 추가하고 다음 코드를 추가합니다.
안으로ViewPager
:
public void notifyItemChanged(Object oldItem, Object newItem) {
if (mItems != null) {
for (ItemInfo itemInfo : mItems) {
if (itemInfo.object.equals(oldItem)) {
itemInfo.object = newItem;
}
}
}
invalidate();
}
fragmentStatePagerAdapter에 입력합니다.
public void replaceFragmetns(ViewPager container, Fragment oldFragment, Fragment newFragment) {
startUpdate(container);
// remove old fragment
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
int position = getFragmentPosition(oldFragment);
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, null);
mFragments.set(position, null);
mCurTransaction.remove(oldFragment);
// add new fragment
while (mFragments.size() <= position) {
mFragments.add(null);
}
mFragments.set(position, newFragment);
mCurTransaction.add(container.getId(), newFragment);
finishUpdate(container);
// ensure getItem returns newFragemtn after calling handleGetItemInbalidated()
handleGetItemInbalidated(container, oldFragment, newFragment);
container.notifyItemChanged(oldFragment, newFragment);
}
protected abstract void handleGetItemInbalidated(View container, Fragment oldFragment, Fragment newFragment);
protected abstract int getFragmentPosition(Fragment fragment);
handleGetItemInvalidated()
다음 번 합니다.getItem()
그것은 새로운 조각으로 돌아옵니다.getFragmentPosition()
어댑터에 있는 조각의 위치를 반환합니다.
이제 프래그먼트 호출을 대체하려면
mAdapter.replaceFragmetns(mViewPager, oldFragment, newFragment);
만약 당신이 예시적인 프로젝트에 관심이 있다면 나에게 출처를 물어 보세요.
Android Android 잘 .의 해결책은 가 이지만, 처럼 수 되었습니다.FrgmentTransaction.addToBackStack(null)
그러나 이를 추가하기만 하면 ViewPager에 알리지 않고 Fragment만 교체됩니다.을 이 된 기능과 이전 수 있습니다.onBackPressed()
방법. 큰 은 한 번에 의 백클릭이 가장 큰 단점은 한 번에 하나씩만 되돌아가기 때문에 여러 번의 백클릭이 발생할 수 있다는 것입니다될 수 입니다.
private ArrayList<Fragment> bFragments = new ArrayList<Fragment>();
private ArrayList<Integer> bPosition = new ArrayList<Integer>();
public void replaceFragmentsWithBackOut(ViewPager container, Fragment oldFragment, Fragment newFragment) {
startUpdate(container);
// remove old fragment
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
int position = getFragmentPosition(oldFragment);
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
//Add Fragment to Back List
bFragments.add(oldFragment);
//Add Pager Position to Back List
bPosition.add(position);
mSavedState.set(position, null);
mFragments.set(position, null);
mCurTransaction.remove(oldFragment);
// add new fragment
while (mFragments.size() <= position) {
mFragments.add(null);
}
mFragments.set(position, newFragment);
mCurTransaction.add(container.getId(), newFragment);
finishUpdate(container);
// ensure getItem returns newFragemtn after calling handleGetItemInbalidated()
handleGetItemInvalidated(container, oldFragment, newFragment);
container.notifyItemChanged(oldFragment, newFragment);
}
public boolean popBackImmediate(ViewPager container){
int bFragSize = bFragments.size();
int bPosSize = bPosition.size();
if(bFragSize>0 && bPosSize>0){
if(bFragSize==bPosSize){
int last = bFragSize-1;
int position = bPosition.get(last);
//Returns Fragment Currently at this position
Fragment replacedFragment = mFragments.get(position);
Fragment originalFragment = bFragments.get(last);
this.replaceFragments(container, replacedFragment, originalFragment);
bPosition.remove(last);
bFragments.remove(last);
return true;
}
}
return false;
}
누군가에게 도움이 되길 바랍니다.
.getFragmentPosition()
가나 됐군요,나getItem()
역으로이 어디로 가는지 알고 , .어떤 파편이 어디로 가는지 알고 있으니, 정확한 위치를 돌려줘야 합니다.예는 다음과 같습니다.
@Override
protected int getFragmentPosition(Fragment fragment) {
if(fragment.equals(originalFragment1)){
return 0;
}
if(fragment.equals(replacementFragment1)){
return 0;
}
if(fragment.equals(Fragment2)){
return 1;
}
return -1;
}
의 에onCreateView
법,container
입니다.ViewPager
사례.
그래서, 그냥 전화로
ViewPager vpViewPager = (ViewPager) container;
vpViewPager.setCurrentItem(1);
입니다의 합니다.ViewPager
.
이 문제에 대한 저의 비교적 간단한 해결책은 다음과 같습니다.이 다를 입니다.FragmentStatePagerAdapter
FragmentPagerAdapter
전자는 사용하지 않은 조각을 제거하고 후자는 인스턴스를 유지하기 때문입니다.입니다의 입니다.POSITION_NONE
ingetItem().내 파편을 추적하기 위해 간단한 목록을 사용했습니다.저의 요구사항은 프래그먼트의 전체 목록을 한 번에 새로운 목록으로 교체하는 것이었지만, 아래는 개별 프래그먼트를 교체하기 위해 쉽게 수정할 수 있었습니다.
public class MyFragmentAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragmentList = new ArrayList<Fragment>();
private List<String> tabTitleList = new ArrayList<String>();
public MyFragmentAdapter(FragmentManager fm) {
super(fm);
}
public void addFragments(List<Fragment> fragments, List<String> titles) {
fragmentList.clear();
tabTitleList.clear();
fragmentList.addAll(fragments);
tabTitleList.addAll(titles);
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object) {
if (fragmentList.contains(object)) {
return POSITION_UNCHANGED;
}
return POSITION_NONE;
}
@Override
public Fragment getItem(int item) {
if (item >= fragmentList.size()) {
return null;
}
return fragmentList.get(item);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return tabTitleList.get(position);
}
}
저는 스택스와 함께 작업하는 솔루션도 만들었습니다.모듈식 접근 방식이므로 각 Fragment 및 Detail Fragment를 지정할 필요가 없습니다.FragmentPagerAdapter
에 구축되어 이것은 제가 구글 데모 앱에서 나온 것이 맞다면 액션바 셜록의 예제 위에 만들어 졌습니다.
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*
* Changed to support more Layers of fragments on each Tab.
* by sebnapi (2012)
*
*/
public class TabsAdapter extends FragmentPagerAdapter
implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final TabHost mTabHost;
private final ViewPager mViewPager;
private ArrayList<String> mTabTags = new ArrayList<String>();
private HashMap<String, Stack<TabInfo>> mTabStackMap = new HashMap<String, Stack<TabInfo>>();
static final class TabInfo {
public final String tag;
public final Class<?> clss;
public Bundle args;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
public DummyTabFactory(Context context) {
mContext = context;
}
@Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public interface SaveStateBundle{
public Bundle onRemoveFragment(Bundle outState);
}
public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mTabHost = tabHost;
mViewPager = pager;
mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
/**
* Add a Tab which will have Fragment Stack. Add Fragments on this Stack by using
* addFragment(FragmentManager fm, String _tag, Class<?> _class, Bundle _args)
* The Stack will hold always the default Fragment u add here.
*
* DON'T ADD Tabs with same tag, it's not beeing checked and results in unexpected
* beahvior.
*
* @param tabSpec
* @param clss
* @param args
*/
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args){
Stack<TabInfo> tabStack = new Stack<TabInfo>();
tabSpec.setContent(new DummyTabFactory(mContext));
mTabHost.addTab(tabSpec);
String tag = tabSpec.getTag();
TabInfo info = new TabInfo(tag, clss, args);
mTabTags.add(tag); // to know the position of the tab tag
tabStack.add(info);
mTabStackMap.put(tag, tabStack);
notifyDataSetChanged();
}
/**
* Will add the Fragment to Tab with the Tag _tag. Provide the Class of the Fragment
* it will be instantiated by this object. Proivde _args for your Fragment.
*
* @param fm
* @param _tag
* @param _class
* @param _args
*/
public void addFragment(FragmentManager fm, String _tag, Class<?> _class, Bundle _args){
TabInfo info = new TabInfo(_tag, _class, _args);
Stack<TabInfo> tabStack = mTabStackMap.get(_tag);
Fragment frag = fm.findFragmentByTag("android:switcher:" + mViewPager.getId() + ":" + mTabTags.indexOf(_tag));
if(frag instanceof SaveStateBundle){
Bundle b = new Bundle();
((SaveStateBundle) frag).onRemoveFragment(b);
tabStack.peek().args = b;
}
tabStack.add(info);
FragmentTransaction ft = fm.beginTransaction();
ft.remove(frag).commit();
notifyDataSetChanged();
}
/**
* Will pop the Fragment added to the Tab with the Tag _tag
*
* @param fm
* @param _tag
* @return
*/
public boolean popFragment(FragmentManager fm, String _tag){
Stack<TabInfo> tabStack = mTabStackMap.get(_tag);
if(tabStack.size()>1){
tabStack.pop();
Fragment frag = fm.findFragmentByTag("android:switcher:" + mViewPager.getId() + ":" + mTabTags.indexOf(_tag));
FragmentTransaction ft = fm.beginTransaction();
ft.remove(frag).commit();
notifyDataSetChanged();
return true;
}
return false;
}
public boolean back(FragmentManager fm) {
int position = mViewPager.getCurrentItem();
return popFragment(fm, mTabTags.get(position));
}
@Override
public int getCount() {
return mTabStackMap.size();
}
@Override
public int getItemPosition(Object object) {
ArrayList<Class<?>> positionNoneHack = new ArrayList<Class<?>>();
for(Stack<TabInfo> tabStack: mTabStackMap.values()){
positionNoneHack.add(tabStack.peek().clss);
} // if the object class lies on top of our stacks, we return default
if(positionNoneHack.contains(object.getClass())){
return POSITION_UNCHANGED;
}
return POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
Stack<TabInfo> tabStack = mTabStackMap.get(mTabTags.get(position));
TabInfo info = tabStack.peek();
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public void onTabChanged(String tabId) {
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
// Unfortunately when TabHost changes the current tab, it kindly
// also takes care of putting focus on it when not in touch mode.
// The jerk.
// This hack tries to prevent this from pulling focus out of our
// ViewPager.
TabWidget widget = mTabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
기본 활동에서 뒤로 단추 기능을 사용하려면 다음을 추가합니다.
@Override
public void onBackPressed() {
if (!mTabsAdapter.back(getSupportFragmentManager())) {
super.onBackPressed();
}
}
조각 상태를 제거할 때 저장하려면요.프래그먼트가 인터페이스를 구현하도록 합니다.SaveStateBundle
함수에 저장 상태가 포함된 번들을 반환합니다.기에서 한 후 :this.getArguments()
.
다음과 같은 탭을 인스턴스화할 수 있습니다.
mTabsAdapter.addTab(mTabHost.newTabSpec("firstTabTag").setIndicator("First Tab Title"),
FirstFragmentActivity.FirstFragmentFragment.class, null);
탭 스택 위에 조각을 추가하려는 경우에도 유사하게 작동합니다.중요:제 생각에는 두 개의 탭 위에 같은 클래스의 인스턴스를 두 개만 올려놓기를 원한다면 작동이 안 될 것 같습니다.저는 이 솔루션을 빠르게 실행했기 때문에 경험을 제공하지 않고 공유만 할 수 있습니다.
보기 페이지에서 조각을 교체하는 것은 상당히 관련되어 있지만 매우 가능하며 매우 매끄럽게 보일 수 있습니다.먼저, 조각 제거 및 추가를 보기 호출기 자체에서 처리하도록 해야 합니다.SearchFragment 내부의 fragment를 교체하면 보기 페이지가 fragment views를 유지합니다.따라서 빈 페이지를 바꾸려고 하면 검색 조각이 제거되므로 빈 페이지가 나타납니다.
해결 방법은 보기 페이지 내에 외부에서 변경된 내용을 처리할 수신기를 만드는 것이므로 먼저 이 코드를 어댑터 맨 아래에 추가합니다.
public interface nextFragmentListener {
public void fragment0Changed(String newFragmentIdentification);
}
그런 다음 조각을 변경할 때 수신기가 되는 개인 클래스를 보기 페이지에 만들어야 합니다.예를 들어, 이런 것을 추가할 수 있습니다.방금 생성된 인터페이스를 구현한다는 점에 주목합니다.그래서 이 메소드를 호출할 때마다 아래 클래스 내부의 코드가 실행됩니다.
private final class fragmentChangeListener implements nextFragmentListener {
@Override
public void fragment0Changed(String fragment) {
//I will explain the purpose of fragment0 in a moment
fragment0 = fragment;
manager.beginTransaction().remove(fragAt0).commit();
switch (fragment){
case "searchFragment":
fragAt0 = SearchFragment.newInstance(listener);
break;
case "searchResultFragment":
fragAt0 = Fragment_Table.newInstance(listener);
break;
}
notifyDataSetChanged();
}
여기서 지적해야 할 사항은 크게 두 가지입니다.
- fragAt0는 "유연한" 프래그먼트입니다.그것은 당신이 그것에 주는 어떤 조각 타입이든 취할 수 있습니다.이를 통해 위치 0의 조각을 원하는 조각으로 변경할 때 가장 친한 친구가 될 수 있습니다.
'New Instance(리스너) Constructor(신규 인스턴스)'에 배치된 리스너에 주목합니다.fragment0Changed(String new Fragment Identification)'를 이렇게 부릅니다.다음 코드는 조각 안에 리스너를 만드는 방법을 보여줍니다.
정적 nextFragmentListenerlistenerListener검색;
public static Fragment_Journals newInstance(nextFragmentListener listener){ listenerSearch = listener; return new Fragment_Journals(); }
은 수 .onPostExecute
private class SearchAsyncTask extends AsyncTask<Void, Void, Void>{
protected Void doInBackground(Void... params){
.
.//some more operation
.
}
protected void onPostExecute(Void param){
listenerSearch.fragment0Changed("searchResultFragment");
}
}
그러면 보기 호출기 내부의 코드가 트리거되어 0 fragAt0 위치의 frag를 새 검색 결과 플래그로 전환합니다.기능하기 전에 보기 페이지에 추가해야 할 작은 조각이 두 개 더 있습니다.
하나는 보기 페이지의 getItem override 메서드에 있습니다.
@Override
public Fragment getItem(int index) {
switch (index) {
case 0:
//this is where it will "remember" which fragment you have just selected. the key is to set a static String fragment at the top of your page that will hold the position that you had just selected.
if(fragAt0 == null){
switch(fragment0){
case "searchFragment":
fragAt0 = FragmentSearch.newInstance(listener);
break;
case "searchResultsFragment":
fragAt0 = FragmentSearchResults.newInstance(listener);
break;
}
}
return fragAt0;
case 1:
// Games fragment activity
return new CreateFragment();
}
이 마지막 작품이 없으면 빈 페이지를 얻을 수 있습니다.약간 어설프지만, 그것은 페이지 보기의 중요한 부분입니다.보기 페이지의 getItemPosition 메서드를 재정의해야 합니다.일반적으로 이 메서드는 보기 페이지에 모든 것을 동일하게 유지하도록 지시하는 POSITION_UNCHANGEED를 반환하므로 getItem이 호출되어 새 조각을 페이지에 배치하지 않습니다.여기 당신이 할 수 있는 일의 예가 있습니다.
public int getItemPosition(Object object)
{
//object is the current fragment displayed at position 0.
if(object instanceof SearchFragment && fragAt0 instanceof SearchResultFragment){
return POSITION_NONE;
//this condition is for when you press back
}else if{(object instanceof SearchResultFragment && fragAt0 instanceof SearchFragment){
return POSITION_NONE;
}
return POSITION_UNCHANGED
}
말씀드린 것처럼 코드가 굉장히 많이 관여하지만, 기본적으로 사용자의 상황에 맞는 맞춤 어댑터를 만들어야 합니다.제가 말한 것들은 조각을 바꾸는 것을 가능하게 할 것입니다.참을성 있게 모든 것을 담글 때까지 오랜 시간이 걸릴 것 같지만, 모든 것이 이해가 될 것입니다.정말 매끄럽게 보이는 어플리케이션을 만들 수 있기 때문에 시간을 끄는 것은 가치가 있습니다.
뒤로 버튼을 다루기 위한 너깃은 여기 있습니다.기본 활동에 이 내용을 입력합니다.
public void onBackPressed() {
if(mViewPager.getCurrentItem() == 0) {
if(pagerAdapter.getItem(0) instanceof FragmentSearchResults){
((Fragment_Table) pagerAdapter.getItem(0)).backPressed();
}else if (pagerAdapter.getItem(0) instanceof FragmentSearch) {
finish();
}
}
fragment0이 변경된 fragmentSearchResults 내부에 backPressed() 메서드를 만들어야 합니다.이것은 이전에 보여준 코드와 함께 뒤로 버튼을 누르는 것을 처리할 것입니다.보기 페이지를 변경하려면 코드에 행운을 빕니다.많은 작업이 필요하고, 제가 찾은 한 빠른 적응은 없습니다.내가 말했듯이, 당신은 기본적으로 사용자 정의 보기 호출기 어댑터를 만들고, 수신기를 사용하여 필요한 모든 변경 사항을 처리하도록 하고 있습니다.
이것이 제가 그것을 이루기 위한 방법입니다.
하기 Root_fragment
에서 안에viewPager
할 탭 fragment
트(event. 예)
@Override
public Fragment getItem(int position) {
if(position==0)
return RootTabFragment.newInstance();
else
return SecondPagerFragment.newInstance();
}
RootTabFragment
.FragmentLayout
프래그먼트 변경을 위해.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
RootTabFragment
onCreateView
,fragmentChange
당신을 위하여FirstPagerFragment
getChildFragmentManager().beginTransaction().replace(R.id.root_frame, FirstPagerFragment.newInstance()).commit();
다음 합니다를 합니다.onClick
.FirstPagerFragment
조각들을 또 그렇게 바꿔놓습니다.
getChildFragmentManager().beginTransaction().replace(R.id.root_frame, NextFragment.newInstance()).commit();
이게 도움이 되길 바랍니다.
중간에 새 조각을 추가하거나 기존 조각을 교체하더라도 효과가 좋은 간단한 솔루션을 찾았습니다.다를 .getItemId()
각 프래그먼트에 대해 고유 ID를 반환해야 합니다.기본적으로 위치를 지정하지 않습니다.
있습니다.
public class DynamicPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Page> mPages = new ArrayList<Page>();
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
public DynamicPagerAdapter(FragmentManager fm) {
super(fm);
}
public void replacePage(int position, Page page) {
mPages.set(position, page);
notifyDataSetChanged();
}
public void setPages(ArrayList<Page> pages) {
mPages = pages;
notifyDataSetChanged();
}
@Override
public Fragment getItem(int position) {
if (mPages.get(position).mPageType == PageType.FIRST) {
return FirstFragment.newInstance(mPages.get(position));
} else {
return SecondFragment.newInstance(mPages.get(position));
}
}
@Override
public int getCount() {
return mPages.size();
}
@Override
public long getItemId(int position) {
// return unique id
return mPages.get(position).getId();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
while (mFragments.size() <= position) {
mFragments.add(null);
}
mFragments.set(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mFragments.set(position, null);
}
@Override
public int getItemPosition(Object object) {
PagerFragment pagerFragment = (PagerFragment) object;
Page page = pagerFragment.getPage();
int position = mFragments.indexOf(pagerFragment);
if (page.equals(mPages.get(position))) {
return POSITION_UNCHANGED;
} else {
return POSITION_NONE;
}
}
}
이 에서는 :FirstFragment
그리고.SecondFragment
는 PageFragment인합니다.getPage()
.
나는 wize와 비슷한 일을 하고 있지만 내 대답은 당신이 원할 때 언제든지 두 조각 사이를 바꿀 수 있습니다.그리고 wiz 답변과 함께 화면의 방향을 바꿀 때 몇 가지 문제가 있습니다.호출기 어댑터의 모양은 다음과 같습니다.
public class MyAdapter extends FragmentPagerAdapter
{
static final int NUM_ITEMS = 2;
private final FragmentManager mFragmentManager;
private Fragment mFragmentAtPos0;
private Map<Integer, String> mFragmentTags;
private boolean isNextFragment=false;
public MyAdapter(FragmentManager fm)
{
super(fm);
mFragmentManager = fm;
mFragmentTags = new HashMap<Integer, String>();
}
@Override
public Fragment getItem(int position)
{
if (position == 0)
{
if (isPager) {
mFragmentAtPos0 = new FirstPageFragment();
} else {
mFragmentAtPos0 = new NextFragment();
}
return mFragmentAtPos0;
}
else
return SecondPageFragment.newInstance();
}
@Override
public int getCount()
{
return NUM_ITEMS;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
// record the fragment tag here.
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
public void onChange(boolean isNextFragment) {
if (mFragmentAtPos0 == null)
mFragmentAtPos0 = getFragment(0);
if (mFragmentAtPos0 != null)
mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();
if (!isNextFragment) {
mFragmentAtFlashcards = new FirstPageFragment();
} else {
mFragmentAtFlashcards = new NextFragment();
}
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object)
{
if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment)
return POSITION_NONE;
if (object instanceof NextFragment && mFragmentAtPos0 instanceof FirstPageFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return mFragmentManager.findFragmentByTag(tag);
}
}
어댑터 컨테이너를 부착할 때 단편에 넣도록 어댑터 컨테이너 작업에서 구현한 리스너, 다음 작업입니다.
public class PagerContainerActivity extends AppCompatActivity implements ChangeFragmentListener {
//...
@Override
public void onChange(boolean isNextFragment) {
if (pagerAdapter != null)
pagerAdapter.onChange(isNextFragment);
}
//...
}
그런 다음 호출을 첨부할 때 수신기를 넣는 조각에서 다음을 수행합니다.
public class FirstPageFragment extends Fragment{
private ChangeFragmentListener changeFragmentListener;
//...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
changeFragmentListener = ((PagerContainerActivity) activity);
}
@Override
public void onDetach() {
super.onDetach();
changeFragmentListener = null;
}
//...
//in the on click to change the fragment
changeFragmentListener.onChange(true);
//...
}
그리고 마지막으로 듣는 사람:
public interface changeFragmentListener {
void onChange(boolean isNextFragment);
}
저는 @wize와 @mdelolmo의 답변을 따랐고 해결책을 얻었습니다.고마워요 톤즈.하지만 메모리 소비를 개선하기 위해 이 솔루션들을 조금 조정했습니다.
관찰한 문제:
그들은 다음과 같은 경우를 저장합니다.Fragment
대체된 것입니다.제 에는,는을 입니다.MapView
돈이 많이 든다고 생각했습니다.그래서, 저는 계속 유지하고 있습니다.FragmentPagerPositionChanged (POSITION_NONE or POSITION_UNCHANGED)
Fragment
그 자체.
이것이 저의 실행입니다.
public static class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
private SwitchFragListener mSwitchFragListener;
private Switch mToggle;
private int pagerAdapterPosChanged = POSITION_UNCHANGED;
private static final int TOGGLE_ENABLE_POS = 2;
public DemoCollectionPagerAdapter(FragmentManager fm, Switch toggle) {
super(fm);
mToggle = toggle;
mSwitchFragListener = new SwitchFragListener();
mToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mSwitchFragListener.onSwitchToNextFragment();
}
});
}
@Override
public Fragment getItem(int i) {
switch (i)
{
case TOGGLE_ENABLE_POS:
if(mToggle.isChecked())
{
return TabReplaceFragment.getInstance();
}else
{
return DemoTab2Fragment.getInstance(i);
}
default:
return DemoTabFragment.getInstance(i);
}
}
@Override
public int getCount() {
return 5;
}
@Override
public CharSequence getPageTitle(int position) {
return "Tab " + (position + 1);
}
@Override
public int getItemPosition(Object object) {
// This check make sures getItem() is called only for the required Fragment
if (object instanceof TabReplaceFragment
|| object instanceof DemoTab2Fragment)
return pagerAdapterPosChanged;
return POSITION_UNCHANGED;
}
/**
* Switch fragments Interface implementation
*/
private final class SwitchFragListener implements
SwitchFragInterface {
SwitchFragListener() {}
public void onSwitchToNextFragment() {
pagerAdapterPosChanged = POSITION_NONE;
notifyDataSetChanged();
}
}
/**
* Interface to switch frags
*/
private interface SwitchFragInterface{
void onSwitchToNextFragment();
}
}
데모 링크가 여기 있습니다.https://youtu.be/l_62uhKkLyM
데모용으로 2개의 프래그먼트를 사용하였습니다.TabReplaceFragment
그리고.DemoTab2Fragment
2번 위치에서내가 사용하는 다른 모든 케이스들은DemoTabFragment
들면
설명:
를 지나갑니다.Switch
[에서 [활동]로로 이동합니다.DemoCollectionPagerAdapter
이 스위치의 상태에 따라 올바른 조각을 표시합니다.하는 겁니다.SwitchFragListener
의onSwitchToNextFragment
를 바꾸는 합니다.pagerAdapterPosChanged
POSITION_NONE
. POSITION_NONE에 대한 자세한 내용을 확인해보세요.그러면 getItem이 무효화되고 올바른 조각을 인스턴스화하는 로직이 있습니다.죄송합니다, 설명이 좀 지저분하다면요.
다시 한번 @wize와 @mdelolmo님의 독창적인 아이디어에 큰 감사를 드립니다.
도움이 되었으면 좋겠습니다. :)
이 구현에 결함이 있으면 알려주십시오.그것은 제 프로젝트에 큰 도움이 될 것입니다.
연구 끝에 짧은 코드로 해결책을 찾았습니다.먼저 fragment에 공용 인스턴스를 만들고 방향이 변경되지 않는 fragment가 변경되면 SaveInstanceState에서 fragment를 제거합니다.
@Override
public void onSaveInstanceState(Bundle outState) {
if (null != mCalFragment) {
FragmentTransaction bt = getChildFragmentManager().beginTransaction();
bt.remove(mFragment);
bt.commit();
}
super.onSaveInstanceState(outState);
}
언급URL : https://stackoverflow.com/questions/7723964/replace-fragment-inside-a-viewpager
'sourcecode' 카테고리의 다른 글
PHP 읽기 전용 속성? (0) | 2023.10.10 |
---|---|
mysql 결과에서 제외할 사용자 호스트 쌍 제공 (0) | 2023.10.10 |
이 Oracle ORA-01403을 처리하는 올바른 방법은 무엇입니까? 데이터를 찾을 수 없음 예외? (0) | 2023.10.10 |
농담에서 스파이를 리셋하거나 클리어하는 방법은? (0) | 2023.10.10 |
my.ini에서 character_set_database 및 collation_database를 outf8로 설정하는 방법은 무엇입니까? (0) | 2023.10.10 |