【问题标题】:Change fragment visibility in runtime when the fragment was created using FragmentPagerAdapter使用 FragmentPagerAdapter 创建片段时在运行时更改片段可见性
【发布时间】:2014-03-17 10:32:25
【问题描述】:

我正在尝试创建我的第一个 Android 应用程序,如下所示:有多个由 FragmentPagerAdapter 初始化的片段的主要活动。还有另一个活动(SettingsActivity),我想在其中列出所有片段名称并允许隐藏其中一些。要隐藏它们,我想使用以下内容:

FragmentManager fm=getFragmentManager();
Fragment myFragment=fm.findFragmentByTag("tag");
fm.beginTransaction().hide(myFragment).commit();

问题是我不知道片段 ID 或标签,不确定它们是否存在。我怎样才能得到它们?我应该切换到 XML 定义以使其成为可能吗?

适配器:

public class TabsPagerAdapter extends FragmentPagerAdapter {

public TabsPagerAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int index) {
    switch (index){
    case 0:
        return new CoverFragment();
    case 1:
        return new NumbersConverterFragment();
    case 2:
        return new TempConverterFragment();
    case 3:
        return new LengthConverterFragment();
    case 4:
        return new AreaConverterFragment();
    case 5:
        return new VolumeConverterFragment();
    case 6:
        return new WeightConverterFragment();
    case 7:
        return new SpeedConverterFragment();
    }
    return null;
}

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

主要活动:

public class MainActivity extends FragmentActivity implements ActionBar.TabListener {

private ViewPager viewPager;
private TabsPagerAdapter tabsPagerAdapter;
private ActionBar actionBar;

@Override
protected void onCreate(Bundle savedInstanceState) {

   String[] tabs={getString(R.string.title_section0), getString(R.string.title_section1),getString(R.string.title_section2)};

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    viewPager=(ViewPager) findViewById(R.id.pager);
    actionBar=getActionBar();
    tabsPagerAdapter=new TabsPagerAdapter(getSupportFragmentManager());

    viewPager.setAdapter(tabsPagerAdapter);
    actionBar.setHomeButtonEnabled(false);
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    for(String tab : tabs){
    actionBar.addTab(actionBar.newTab().setText(tab).setTabListener(this));
    }


    viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }
     ...
    });

}

片段布局:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#fbfdfb"
    >


     <TextView android:text="@string/celsius_" android:id="@+id/textView1" 
      android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
    <EditText android:text="" android:id="@+id/txtCelsius" android:layout_width="match_parent" 
      android:layout_height="wrap_content"></EditText>

    <TextView android:text="@string/fahrenheit_" android:id="@+id/textView1" 
      android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
    <EditText android:text="" android:id="@+id/txtFahrenheit" android:layout_width="match_parent" 
      android:layout_height="wrap_content"></EditText>

    <TextView android:text="@string/kelvin_" android:id="@+id/textView1" 
      android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
    <EditText android:text="" android:id="@+id/txtKelvin" android:layout_width="match_parent" 
      android:layout_height="wrap_content"></EditText>    

 </LinearLayout>

片段类:

public class TempConverterFragment extends Fragment {

EditText txtCelsius, txtFahrenheit, txtKelvin;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.temp_converter_fragment, container, false);

    txtCelsius = (EditText) rootView.findViewById(R.id.txtCelsius);
    txtFahrenheit = (EditText) rootView.findViewById(R.id.txtFahrenheit);
    txtKelvin = (EditText) rootView.findViewById(R.id.txtKelvin);
      ...
     }
  ...
}

提前致谢。

【问题讨论】:

    标签: java android android-fragments visibility fragmentpageradapter


    【解决方案1】:

    如果 SettingsActivity 不是持有 FragmentPagerAdapter 的 Activity,那么您将不得不重新创建所有 Fragment。片段的性质与它的活动密切相关。

    如果 SettingsActivity 是持有 FragmentPagerAdapter 的 Activity,那么我记得,FragmentPagerAdapter 会尽快初始化所有 8 个 Fragment,以便在您滑动时准备好它们,这与 FragmentStatePagerAdapter 不同。这意味着您应该(我认为)能够在构造函数 TabsPagerAdapter 中创建每个片段并保留对它们的引用,您可以使用 TabsPagerAdapter 上的 getter 方法访问它们。

    这是一个如何轻松访问您的页面适配器片段的示例:

    public class DisplayPagerAdapter extends FragmentStatePagerAdapter {
    
        private static final String TAG = "DisplayPagerAdapter";
    
        SparseArray<DisplayFragment> registeredFragments = new SparseArray<DisplayFragment>();
    
        @Inject DisplayCoreModule display;
    
        public DisplayPagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public int getCount() {
            return (display != null && display.getPagesCount() > 0) ? display.getPagesCount() : 1;
        }
    
        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
    
    
        @Override
        public Fragment getItem(int position) {
            Log.d(TAG, "getItem " + position);
            return DisplayFragment.newInstance(position); 
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
            if (display != null && display.getPagesCount() > 0) {
                return "Side " + (position+1);
            } else {
                return super.getPageTitle(position);
            }
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Log.d(TAG, "instantiateItem " + position);
            DisplayFragment fragment = (DisplayFragment) super.instantiateItem(container, position);
            registeredFragments.put(position, fragment);
            return fragment;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            Log.d(TAG, "destroyItem " + position);
            registeredFragments.remove(position);
            super.destroyItem(container, position, object);
        }
    
        public Fragment getRegisteredFragment(int position) {
            return registeredFragments.get(position);
        }
    
        public SparseArray<DisplayFragment> getRegisteredFragments() {
            return registeredFragments;
        }
    
    
    }
    

    现在,如果您实现了注册片段的这种用法,您可以调用tabsPagerAdapter.getRegisteredFragment(2) 来获取您的 TempConverterFragment。

    SparseArray&lt;DisplayFragment&gt; 在你的情况下应该是 SparseArray&lt;Fragment&gt;

    现在这并不能解决您的 SettingsActivity 问题。但是,如果我对您的理解正确,那么直接在 SettingsActivity 的布局 XML 中添加您想要的片段是有意义的。然后很容易暂时隐藏片段或任何使用:

    FragmentManager fm=getFragmentManager();
    Fragment myFragment=fm.findFragmentById(R.id.frag_tempconverter)
    fm.beginTransaction().hide(myFragment).commit();
    

    注意findFragmentById 的使用。该标签通常用于动态添加的片段(至少在我看来)。 findFragmentById 如果在 XML 布局中定义,肯定会返回一个片段,但为了清楚起见,它将是片段的一个新实例。

    解决您的问题:

    如果我将片段移动到主活动 XML 会怎样?这不是让事情变得更简单吗

    不这么认为,更新后的答案显示了如何轻松访问片段(从您的主要活动中)。

    虽然不确定我可以在 SettingsActivity 中使用 FragmentManager

    当然可以。您可以添加新片段、访问可用片段(使用 findById 从预定义的 XML 或使用 findByTag 动态添加)。但是,您不能访问与您的主要活动保持相同的片段实例。

    要在片段和两个活动之间共享信息,您需要以某种方式持久化片段的状态(这是一个不同的主题)。

    总而言之,我认为您走在正确的道路上,您只需将正确的拼图组合起来 :)

    【讨论】:

    • 谢谢!我错过了这些片段与活动相关联。 SettingsActivity 不持有适配器。你说“必须重新创建片段”是什么意思?如果我将片段移动到主要活动 XML 会怎样?它不会让事情变得更简单 - 我将能够通过首先访问活动来访问他们的 ID - findViewById(R.id.
    • 没问题 :) 用一些希望有用的东西更新了我的答案
    • 非常感谢您提供的示例。我意识到我做错了什么。我会在一两天内继续这个。
    • 没问题,乐于助人:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-27
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 2012-09-15
    • 2014-06-07
    • 1970-01-01
    相关资源
    最近更新 更多