29

Trong ứng dụng tôi đang phát triển, tôi đang sử dụng một ViewPager với các đoạn và mỗi đoạn xây dựng trình đơn riêng của mình độc lập với tất cả các mảnh khác trong ViewPager.Các mục hành động từ phân đoạn ban đầu của Viewpager không được hiển thị

Vấn đề là đôi khi các mảnh được khởi tạo bởi ViewPager theo mặc định (tức là ở trạng thái ban đầu) không có các mục của chúng được điền vào menu mục tác vụ. Điều tệ hơn là vấn đề này chỉ xảy ra liên tục. Nếu tôi vuốt qua ViewPager đủ để các mảnh bị buộc phải khởi tạo lại bản thân, khi tôi vuốt lại, trình đơn sẽ điền chính xác.

đang Hoạt động:

package net.solarnz.apps.fragmentsample; 

import android.app.Activity; 
import android.app.Fragment; 
import android.app.FragmentManager; 
import android.os.Bundle; 
import android.support.v13.app.FragmentStatePagerAdapter; 
import android.support.v4.view.ViewPager; 

public class FragmentSampleActivity extends Activity { 
    private ViewPagerAdapter mViewPagerAdapter; 
    private ViewPager mViewPager; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     if (mViewPagerAdapter == null) { 
      mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager()); 
     } 

     mViewPager = (ViewPager) findViewById(R.id.log_pager); 
     mViewPager.setAdapter(mViewPagerAdapter); 
     mViewPager.setCurrentItem(0); 
    } 


    private class ViewPagerAdapter extends FragmentStatePagerAdapter { 
     public ViewPagerAdapter(FragmentManager fm) { 
      super(fm); 
     } 

     @Override 
     public int getCount() { 
      return 8; 
     } 

     @Override 
     public Fragment getItem(int position) { 
      Fragment f = Fragment1.newInstance(position); 
      // f.setRetainInstance(true); 
      f.setHasOptionsMenu(true); 
      return f; 
     } 
    } 
} 

đang Fragment:

package net.solarnz.apps.fragmentsample; 

import android.app.Fragment; 
import android.os.Bundle; 
import android.view.Menu; 
import android.view.MenuInflater; 

public class Fragment1 extends Fragment { 
    int mNum; 

    static Fragment newInstance(int num) { 
     Fragment1 f = new Fragment1(); 

     // Supply num input as an argument. 
     Bundle args = new Bundle(); 
     args.putInt("num", num); 
     f.setArguments(args); 

     return f; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setHasOptionsMenu(true); 
     mNum = getArguments() != null ? getArguments().getInt("num") : 0; 
    } 

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     inflater.inflate(R.menu.menu_list, menu); 
    } 

} 

Layout:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" > 

      <android.support.v4.view.ViewPager 
       android:id="@+id/log_pager" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" /> 
</LinearLayout> 

Menu:

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:id="@+id/menu_refresh" 
      android:title="Refresh" 
      android:icon="@android:drawable/ic_delete" 
      android:showAsAction="ifRoom|withText" /> 
</menu> 

menu Action được dân cư: http://i.stack.imgur.com/QFMDd.png

menu Action không phải là dân cư: http://i.stack.imgur.com/sH5Pp.png

+0

Đồng ý với Solarnz dường như không có cách giải quyết rõ ràng nào. Tôi đã tạo ra một [ứng dụng trình diễn] (https://github.com/snodnipper/page-flipper-race-condition/) cho phép người ta tái tạo lại vấn đề một cách đáng tin cậy. Vấn đề tương tự dường như [được báo cáo trong ActionBarSherlock] (https://github.com/JakeWharton/ActionBarSherlock/issues/351) và tôi đã nêu ra [vấn đề] này (http://code.google.com/p/android/issues/detail? id = 29472) trong trình theo dõi vấn đề android. – snodnipper

Trả lời

21

Bạn nên đọc này (bằng cách xcolw ...)

Qua thử nghiệm nó có vẻ như nguyên nhân gốc rễ là invalidateOptionsMenu nhận được gọi là nhiều hơn một mà không cần nghỉ ngơi trên các chủ đề chính để xử lý công việc xếp hàng. Một đoán - điều này sẽ quan trọng nếu một số phần quan trọng của việc tạo menu được trì hoãn thông qua một bài đăng, để lại thanh hành động ở trạng thái xấu cho đến khi nó chạy.

Có một vài đốm này có thể xảy ra mà không phải là rõ ràng:

  1. gọi viewPager.setCurrentItem nhiều lần cho cùng một mục

  2. gọi viewPager.setCurrentItem trong onCreate của hoạt động này. setCurrentItem gây ra một tùy chọn trình đơn vô hiệu, mà là ngay lập tức sau đó là tùy chọn trình đơn của hoạt động làm mất hiệu lực

Cách giải quyết tôi đã tìm thấy cho mỗi

  1. Guard cuộc gọi đến ViewPager.setCurrentItem

    if (viewPager.getCurrentItem() != position) 
        viewPager.setCurrentItem(position); 
    
  2. Hoãn cuộc gọi đến viewPager.setCurrentItem trong onCreate

    public void onCreate(...) { 
        ... 
        view.post(new Runnable() { 
         public void run() { 
          // guarded viewPager.setCurrentItem 
         } 
        } 
    } 
    

Sau những thay đổi tùy chọn trình đơn bên trong xem pager dường như làm việc như mong đợi. Tôi hy vọng ai đó có thể làm sáng tỏ điều này.

nguồnhttp://code.google.com/p/android/issues/detail?id=29472

+0

Tuyệt vời. Cảm ơn. –

+0

Xin vui lòng, cung cấp đầy đủ snipet làm thế nào để sử dụng điều này với viewpager không có tab, không rõ ràng cho tôi. Cảm ơn. –

+0

Nó đã không làm việc cho tôi. mViewPager.post (new Runnable() {@Override public void run() { mViewPager.setAdapter (FragPagerAdapter mới (getSupportFragmentManager(), MainActivity.this));! if (mViewPager.getCurrentItem() = 1) { mViewPager.setCurrentItem (1); } } }); –

8

Câu trả lời đơn giản là không sử dụng menu trong mảnh vỡ trong ViewPager. Nếu bạn cần sử dụng các menu trong các đoạn, điều tôi đề nghị là tải trình đơn thông qua phương thức onCreateOptionsMenu trong Hoạt động gốc. Rõ ràng bạn sẽ cần phải có khả năng xác định menu nào sẽ hiển thị.

Tôi đã có thể đạt được điều này bằng cách sử dụng phản chiếu lớp học. Bạn cũng sẽ cần phải sử dụng phương thức invalidateOptionsMenu mỗi khi bạn chuyển đổi các trang. Bạn sẽ cần một OnPageChangeListener để gọi nó khi ViewPager thay đổi các trang.

+0

Bạn có thể chia sẻ mã cho điều đó không? –

0

Đầu tiên tạo ra một phương thức trong lớp phụ của FragmentPagerAdapter để có được những đoạn hiện

public SherlockFragment getFragment() { 
    return currentFragment; 
} 

     @Override 
public void onTabSelected(final Tab tab, FragmentTransaction ft) { 

    ((SherlockFragmentActivity) mContext).invalidateOptionsMenu(); 
    Fragment f = ((SherlockFragmentActivity) mContext) 
      .getSupportFragmentManager().findFragmentByTag(
        makeFragmentName(tab.getPosition())); 

    currentFragment=(SherlockFragment) f; 
} 

Bây giờ ghi đè dưới phương pháp trong chính Actvity

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    if (mTabsAdapter.getPositionOfTabSelected() != 0) { 
     menu.add("Read").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 
     menu.add("Write").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 
     menu.add("Clear").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 
     menu.add("Factory data reset").setShowAsAction(
       MenuItem.SHOW_AS_ACTION_IF_ROOM); 
    } 

    return super.onCreateOptionsMenu(menu); 
} 

Bây giờ gọi onOptionItemSelected từ hoạt động thành phân đoạn

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    mTabsAdapter.getFragment().onOptionsItemSelected(item); 
    return super.onOptionsItemSelected(item); 
} 
3

Tôi cũng gặp vấn đề tương tự. Trong trường hợp của tôi, tôi có một hoạt động với chế độ xem có chứa hai đoạn, mỗi đoạn sẽ làm tăng trình đơn tác vụ của riêng nó nhưng trình đơn tác vụ phân đoạn không được hiển thị.

Xem đang pager bộ chuyển đổi

public class ScreensAdapter extends FragmentPagerAdapter { 

    public TrackerScreensAdapter(Context context, FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public int getCount() { 
     return 2; 
    } 

    public Fragment getItem(int position) { 
     Fragment fragment = null; 
     switch (position){ 
      case 0: 
       fragment = new Fragment1(); 
       break; 
      case 1: 
       fragment = new Fragment2(); 
       break; 
     } 
     return fragment; 
    } 

} 

Hoạt động trên tạo

screensAdapter = new ScreensAdapter(this, getFragmentManager()); 
    viewPager.setAdapter(screensAdapter); 

Bằng cách này ViewPager tôi có hai đoạn, mỗi đoạn bắn nhiệm vụ riêng của mình trong onActivityCreated, thu thập số liệu và vẽ bố trí của nó dựa trên thu được dữ liệu. Ngoài ra, mỗi đoạn có trênCreateOptionsMenu

@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 
    setHasOptionsMenu(true); 
    MyTask task = new MyTask(); 
    task.setTaskListener(this); 
    task.execute(); 


} 

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    inflater.inflate(R.menu.fragment_menu, menu); 
} 

Đã dành nhiều lần để giải quyết vấn đề này và tìm ra lý do tại sao menu phân đoạn không hiển thị. Tất cả những gì tôi đã cần là

screenAdapter = new ScreenAdapter(this, getFragmentManager()); 
    viewPager.post(new Runnable() { 
     public void run() { 
      viewPager.setAdapter(screenAdapter); 
     } 
    }); 
+0

Cảm ơn! thiết lập bộ điều hợp bên trong runnable giải quyết nó cho tôi –

0

tôi giải quyết một vấn đề rất tương tự, trong đó các biểu tượng thanh hành động bởi các đoạn giao bên trong một ViewPager đã biến mất onPause(). Chúng sẽ xuất hiện trở lại khi Fragment trở lại xem và người dùng vuốt sang trái hoặc phải, nhưng không phải ngay lập tức. Giải pháp đã gọi notifyDataSetChanged() trên PagerAdapter trong phương thức onResume() của đoạn.

@Override 
public void onResume() { 
    mPagerAdapter.notifyDataSetChanged(); 
} 
0

Tôi đã có vấn đề này với mục Action Bar trong khi tôi đang sử dụng HorizontalScrollView để hiển thị các tab nhưng tôi đã thay đổi để PagerTitleStrip và vấn đề đã được giải quyết.

Có lẽ thông tin này có thể giúp người khác.

0

Trong trường hợp của tôi, tôi đã theo dõi nguyên nhân gốc rễ của vấn đề với những gì tôi tin là lỗi trong FragmentStatePagerAdapter đang gọi Fragment#setMenuVisibility thành sai và không đặt đúng trở lại khi nó khôi phục trạng thái của nó.

Cách giải quyết:

  1. Sử dụng FragmentPagerAdapter thay vì FragmentStatePagerAdapter

  2. Nếu bạn phải sử dụng FragmentStatePagerAdapter, trong bộ chuyển đổi lớp con override setPrimaryItem bạn như vậy:

    @Override 
    public void setPrimaryItem(ViewGroup container, int position, Object object) { 
        super.setPrimaryItem(container, position, object); 
    
        //This is a workaround for a bug in FragmentStatePagerAdapter 
        Fragment currentItem = getItem(position); 
        if (currentItem != null) { 
         currentItem.setMenuVisibility(true); 
         currentItem.setUserVisibleHint(true); 
        } 
    } 
    
+0

Không có phương pháp nào trong số đó hoạt động. – Proverbio