一旦实现了Fragment和ViewPager,就无法编辑某些视图

时间:2013-01-09 18:39:59

标签: android android-fragments android-viewpager layout-inflater

编辑:

从更多的问题来看,我几乎肯定的是问题在于,当我在FragmentActivity的onCreate()方法中夸大布局时,ViewPager中有不同的视图。因此,当我尝试使用xml1.findViewById()访问它们时,它会查看不同的视图。如何访问ViewPager中使用的视图?查看我的FragmentPagerAdapter,看起来片段每次超过1次滑动时都会被创建为新对象。我想要将所有4个视图初始化一次。然后,每当我调用updateUI时,四个视图会立即被更改。所以我可以在他们新近更新的所有四个视图之间滑动。

我尝试使用pagerAdapter.getItem(index).getView().findViewById( ),但它返回NullPointerException。我收到异常后,尝试覆盖getView()类中的Fragment方法。我在方法中添加的只是return view;,其中view是onCreateView方法中返回的View的保存实例。这导致我的ViewPager显示4个空白屏幕以进行滑动。

我将FragmentPagerAdapter实施添加到问题的底部。

结束修改

我尝试使用Fragments来实施ViewPager。我的结果非常奇怪。

private TextView view1a, view1b;
private TextView view2a, view2b;
private TextView view3a, view3b;
private TextView view4a, view4b;
private Spinner spinner1, spinner2, spinner3, spinner4;
private Checkbox check1, check2, check3, check4;

private ViewPager mViewPager;
private View xml1, xml2, xml3, xml4;

public void onCreate( Bundle savedInstanceState ) {
    super.onCreate( savedInstanceState );
    setContentView( R.layout.main_page );

    mViewPager = (ViewPager) findViewById( R.id.pager );
    FragmentManager fm = getSupportFragmentManager();
    MoreParmsFragmentPagerAdapter pagerAdapter = new MoreParmsFragmentPagerAdapter(fm);

    xml1 = LayoutInflater.from( getBaseContext()).inflate( R.layout.xml1, null );
    xml2 = LayoutInflater.from( getBaseContext()).inflate( R.layout.xml2, null );
    xml3 = LayoutInflater.from( getBaseContext()).inflate( R.layout.xml3, null );
    xml4 = LayoutInflater.from( getBaseContext()).inflate( R.layout.xml4, null );
    populateSpinners();
    updateUI();
}


public void populateSpinners() {
    array1Adapter = new ArrayAdapter<String>( this, android.R.layout.simple_spinner_item, res.getStringArray( R.array.array1 )  );
    array1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner1 = (Spinner) xml1.findViewById(R.id.spinner1);
    spinner1.setAdapter(array1Adapter);

    array2Adapter = new ArrayAdapter<String>( this, android.R.layout.simple_spinner_item, res.getStringArray( R.array.array2 )  );
    array2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner2 = (Spinner) xml2.findViewById(R.id.spinner2);
    spinner2.setAdapter(array2Adapter);

    array3Adapter = new ArrayAdapter<String>( this, android.R.layout.simple_spinner_item, res.getStringArray( R.array.array3 )  );
    array3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner3 = (Spinner) xml3.findViewById(R.id.spinner3);
    spinner3.setAdapter(array3Adapter);

    array4Adapter = new ArrayAdapter<String>( this, android.R.layout.simple_spinner_item, res.getStringArray( R.array.array4 )  );
    array4Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner4 = (Spinner) xml4.findViewById(R.id.spinner4);
    spinner4.setAdapter(array4Adapter);
}

public void updateUI() {
    view1a = (TextView) xml1.findViewById( R.id.view_one_a );
    view1b = (TextView) xml1.findViewById( R.id.view_one_b );
    view2a = (TextView) xml2.findViewById( R.id.view_two_a );
    view2b = (TextView) xml2.findViewById( R.id.view_two_b );
    view3a = (TextView) xml3.findViewById( R.id.view_three_a );
    view3b = (TextView) xml3.findViewById( R.id.view_three_b );
    view4a = (TextView) xml4.findViewById( R.id.view_four_a );
    view4b = (TextView) xml4.findViewById( R.id.view_four_b );
    // There is work done here to determine what to set
    // the different TextViews' text to.
    //
    // `view**.setText()` is called for all views above with their respective values.

    spinner1 = (Spinner) xml1.findViewById( R.id.spinner1 );
    spinner2 = (Spinner) xml2.findViewById( R.id.spinner2 );
    spinner3 = (Spinner) xml3.findViewById( R.id.spinner3 );
    spinner4 = (Spinner) xml4.findViewById( R.id.spinner4 );
    // There is work done here to determine what index the Spinners
    // should have selected.
    //
    // `Spinner.setSelection( index ) is called on all spinners.

    check1 = (CheckBox) xml1.findViewById( R.id.check1 );
    check2 = (CheckBox) xml2.findViewById( R.id.check2 );
    check3 = (CheckBox) xml3.findViewById( R.id.check3 );
    check4 = (CheckBox) xml4.findViewById( R.id.check4 );
    // There is work done here to determine whether or not
    // to check the CheckBoxes.
    //
    // CheckBox.setChecked() is called for all checkboxes.
}
}

这是我的Fragment课程的一个例子:

public class xmlOneFragment extends Fragment {
    int mCurrentPage;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /** Getting the arguments to the Bundle object */
        Bundle data = getArguments();

        /** Getting integer data of the key current_page from the bundle */
        mCurrentPage = data.getInt("current_page", 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       View v = inflater.inflate(R.layout.xml1, container,false);
       return v;
    }
}

FIRST 问题是Spinners永远不会填充相应的数组。我的LogCat方法中有populateSpinners()次调用,告诉我我的期望,但Spinners本身并未填充。

SECOND 问题出现在updateUI()方法中。所有findViewById()次调用下面的评论都是我进行某些计算以确定要放入TextViews的文本,设置Spinners的索引以及是否检查CheckBoxes。我有LogCat次调用显示找到的值,它们都是预期的。 调用.setText(), .setSelection(), and .setChecked()方法时,不会显示任何错误,但根本没有设置任何项目。一切都是空白的。

THIRD 问题让我感到困惑。 TextViews现在都有唯一的ID。当我第一次尝试实现此ViewPager时,我使用updateUI()方法处理TextViews而xml*.调用没有findViewById()前缀。

view1a = (TextView) findViewById( R.id.view_one_a );
view1b = (TextView) findViewById( R.id.view_one_b );
view2a = (TextView) findViewById( R.id.view_two_a );
view2b = (TextView) findViewById( R.id.view_two_b );
view3a = (TextView) findViewById( R.id.view_three_a );
view3b = (TextView) findViewById( R.id.view_three_b );
view4a = (TextView) findViewById( R.id.view_four_a );
view4b = (TextView) findViewById( R.id.view_four_b );
// There is work done here to determine what to set
// the different TextViews' text to.
view**.setText( whatever );

此方法产生NullPointerException,但仅在第三页和第四页上使用.setText()调用TextViews时。前两页没有任何例外。所以我评论了第三和第四页。程序运行,前两页在正确的TextViews中显示正确的值。然后我尝试将xml*.添加到findViewById()方法,现在没有抛出异常,但根本没有更新视图。

最后注意事项 ViewPager功能正常,我可以非常好地在适当的布局之间滑动。当我尝试使用我想要的值更新视图时出现问题。我假设问题与我如何夸大布局有关,或者我如何做太多次。第三个问题让我很困惑。我找不到第一页/第二页和第三页/第四页之间的任何差异,但它们显然表现不同。另外,显示的第一个代码块表示为Activity,第二个代码块表示为FragmentActivity

编辑以添加FragmentPagerAdapter

public class MoreParmsFragmentPagerAdapter extends FragmentPagerAdapter {
    final int PAGE_COUNT = 4;

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

    public Fragment getItem( int arg0 ) {
        if( arg0 == 0 ) {
            xmlOneFragment xml1Frag = new xmlOneFragment();
            Bundle data = new Bundle();
            data.putInt( "current_page", arg0 );
            xmlOneFrag.setArguments( data );
            return xmlOneFrag;
        } else if( arg0 == 1 ) {
            xmlTwoFragment xml2Frag = new xmlTwoFragment();
            Bundle data = new Bundle();
            data.putInt( "current_page", arg0 );
            xmlTwoFrag.setArguments( data );
            return xmlTwoFrag;
        } else if( arg0 == 2 ) {
            xmlThreeFragment xml3Frag = new xmlThreeFragment();
            Bundle data = new Bundle();
            data.putInt( "current_page", arg0 );
            xmlThreeFrag.setArguments( data );
            return xmlThreeFrag;
        } else {
            xmlFourFragment xml4Frag = new xmlFourFragment();
            Bundle data = new Bundle();
            data.putInt( "current_page",  arg0 );
            xmlFourFrag.setArguments( data );
            return xmlFourFrag;
        }
    }

    @Override
    public CharSequence getPageTitle(int position) {
        if( position == 0 ) {
            return "xml1";
        } else if( position == 1 ){
            return "xml2";
        } else if( position == 2 ) {
            return "xml3";
        } else {
            return "xml4";
        }
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return PAGE_COUNT;
}
}

编辑2:

private ViewPager mViewPager;
private MoreParmsFragmentPagerAdapter pagerAdapter;
private FragmentManager fm;
private AntiPumpFragment apFrag;
private RelaxedCloseFragment relFrag;
private MiscParmsFragment miscFrag;
private DNP3Fragment dnpFrag;

public void onCreate( Bundle savedInstanceState ) {
    super.onCreate( savedInstanceState );
    mViewPager = (ViewPager) findViewById( R.id.pager );
    fm = getSupportFragmentManager();
    pagerAdapter = new MoreParmsFragmentPagerAdapter(fm);
    mViewPager.setAdapter( pagerAdapter );

    apFrag = (AntiPumpFragment) fm.findFragmentByTag( "android:switcher:" + R.id.pager + ":0" );
    relFrag = (RelaxedCloseFragment) fm.findFragmentByTag( "android:switcher:" + R.id.pager + ":1" );
    miscFrag = (MiscParmsFragment) fm.findFragmentByTag( "android:switcher:" + R.id.pager + ":2" );
    dnpFrag = (DNP3Fragment) fm.findFragmentByTag( "android:switcher:" + R.id.pager + ":3" );

在我的代码中,所有这些片段都返回null。 ViewPager在我的屏幕上正确显示,我可以干净地在所有四个视图之间滑动。但是,我的所有if( apFrag != null )语句都会被跳过。

1 个答案:

答案 0 :(得分:1)

  

第一个问题是Spinners永远不会充满他们的   相应的数组。我的整个过程都有LogCat调用   populateSpinners()方法向我展示了我的期望,但是Spinners   他们自己没有人口。

正如您稍后发现的那样,您没有看到Spinners已初始化,因为您只是使用了Fragments来自ViewPager LayoutInflater的视图,而不是FragmentsActivity中使用的布局文件中展开新视图。初始化此新视图的子视图不会显示任何视觉效果,因为它不存在/显示在ViewGroup的用户界面中,它会“浮动”,等待您将其附加到ActivityView所以它可以显示它有哪些观点。

  

在updateUI()方法中出现了SECOND问题。以下评论   所有findViewById()调用都是我进行某些计算的地方   确定要在TextViews中放入什么文本,设置什么索引   旋转器,以及是否检查CheckBoxes。我有LogCat   显示找到的值的调用,它们都是预期的。   当.setText(),. setSelection()和.setChecked()方法是   调用时,不显示任何错误,但根本没有设置任何项目。   一切都空白。

与一个点相同,您没有初始化显示的视图,您正在更新未附加的ViewPager层次结构。

  

第三个问题让我感到困惑。现在是TextViews   都有唯一的ID。当我第一次尝试实现这个ViewPager时,我   如果没有xml *,updateUI()方法处理TextViews。字首   到findViewById()调用。[...]这个方法产生了一个   NullPointerException,但仅在使用.setText()调用时   第三页和第四页上的TextViews。前两页没有   扔任何例外

也许这会让事情变得清晰:ListView除了允许左右滑动之外,还设计(通过适配器)以允许尽可能少地使用视图(例如ViewPager,它仅为可见行膨胀行。为此,它只构建一定数量的页面。默认情况下,此页数为3(一页可见+每侧一页,因此滑动将是平滑的),ViewPager将在您向前或向后滑动时开始加载其他页面。当您启动NullPointerException时,它将加载第一页(可见的)或下一页(右侧),以便用户可以立即滑动。其他两个页面未加载以提高效率,并且尝试从它们访问窗口小部件将抛出ViewPager,因为它们无法找到。而且,如果用户可能根本看不到这些页面,那么最终你不应该做不必要的工作。现在,您可以修改setOffscreenPageLimit()创建并保留在内存中的页数(使用geItem()并提供一个数字)但是您应该尽量避免它的效率,因为这会加载所有内存中的小部件一下子(在你的情况下,这可能不会那么糟糕,但我不知道你想做什么)。

  

我尝试使用pagerAdapter.getItem(index).getView()。findViewById(),   但它返回NullPointerException。我得到例外后,我   尝试重写我的Fragment类中的getView()方法。我   放入方法是返回视图;,其中视图是保存的实例   onCreateView方法返回的视图。这导致了我的   ViewPager显示4个空白屏幕之间的滑动。

您无法使用适配器的Fragment方法,因为这不会返回ViewPager当前使用的Fragment实例,它会返回 new Activity刚刚实例化。由于它刚刚实例化而未附加到getView(),因此其ViewPager方法不会返回视图。

  

如何访问ViewPager中使用的视图?

这取决于您何时想要访问它们。如果您在Fragments上设置适配器时数据可用,则只需在onCreateViewonActivityCreated方法的Fragment中移动初始化。

如果您想稍后访问ViewPager中的ViewPager,您可以使用小型黑客,知道Fragments添加(暂时)FragmentManagerandroid:switcher:theIdOfTheViewPager:thePositionInTheViewPager中使用Fragment形式的特殊标记。例如,要访问ViewPager的第一个xmlOneFragment first = (xmlOneFragment)getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":0"); // if the fragment is found and its view is available do stuff if (first != null && first.getView() != null) { // do stuff }

ViewPager

不是最佳解决方案,但它会对您有用,直到您对{{1}}更加了解。