1

编辑:

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

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

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

结束编辑

我尝试ViewPager使用Fragments. 我得到了非常奇怪的结果。

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;
    }
}

一个问题是Spinners它们永远不会被相应的数组填充。在我的方法中,有一些LogCat调用populateSpinners()向我展示了我的期望,但Spinners它们本身并没有被填充。

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

第三问题是最让我困惑的。现在TextViews都有唯一的ID。当我第一次尝试实现这个ViewPager时,我让updateUI()方法处理没有调用xml*.前缀的TextViews。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前两页没有抛出任何异常。所以我把第三页和第四页注释掉了。程序运行,前两页在正确的 TextView 中显示了正确的值。然后我尝试添加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 )陈述总是被跳过。

4

1 回答 1

1

第一个问题是 Spinner 永远不会被其对应的数组填充。在我的 populateSpinners() 方法中有 LogCat 调用向我展示了我的期望,但 Spinners 本身没有填充。

正如您后来发现的那样,您看不到Spinners初始化,因为您无需连接到来自 的视图,而是Fragments简单ViewPager使用 a从. 初始化这个新视图的子视图不会显示任何视觉结果,因为它不存在/显示在 UI 的 UI 中,它“浮动”在等待您将其附加到 a中,因此它可以显示它具有的视图。LayoutInflaterFragmentsActivityViewGroupActivity

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

这与一个相同点,您不初始化显示的视图,而是更新未附加的View层次结构。

第三个问题是最让我困惑的。TextViews 现在都有唯一的 ID。当我第一次尝试实现这个 ViewPager 时,我让 updateUI() 方法处理没有 xml* 的 TextViews。findViewById() 调用的前缀。[...]此方法导致 NullPointerException,但仅在使用第三页和第四页上的 TextViews 调用 .setText() 时。前两页没有抛出任何异常

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

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

您不能使用geItem()适配器的方法,因为这不会返回Fragment' 当前使用的实例ViewPager,它将返回一个刚刚实例化的 Fragment实例。由于它只是实例化并且没有附加到Activity,它的getView()方法不会返回视图。

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

这取决于您何时想要访问它们。如果在您设置适配器时数据可用,ViewPager则只需将初始化移动到FragmentsoronCreateView方法onActivityCreated中。

如果您想稍后从 访问Fragment's,您可以使用一个ViewPager小技巧,知道ViewPager添加(现在)Fragments在. 例如,要访问第一个:FragmentManagerandroid:switcher:theIdOfTheViewPager:thePositionInTheViewPagerFragmentViewPager

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.

于 2013-01-10T08:50:38.627 回答