简体   繁体   English

Android中的片段和ViewPager

[英]Fragments and ViewPager in Android

I am having a ViewPager to allow the user to slide between 5 different views where each "view" extends Fragment. 我有一个ViewPager,允许用户在5个不同的视图之间滑动,其中每个“视图”都延伸Fragment。

I have my own adapter which extend FragmentPagerAdapter and which implement getItem() as 我有自己的适配器,该适配器扩展FragmentPagerAdapter并实现getItem()为

@Override public Fragment getItem(int position) {
   switch(position) {
      case 0: 
          return new TextDescriptionFragment();
      // Handle the 4 other cases the same way
   }
}

This works fine and the user can swipe between the 5 different views. 效果很好,用户可以在5个不同的视图之间滑动。 But here comes the problem: Each of the first 4 views contains Views such as Button and EditText which the user can interact with. 但是问题来了:前四个视图中的每个视图都包含用户可以与之交互的诸如Button和EditText之类的视图。

And I then want the last page(Page number 5) to show all the user input values from all the views from the 4 previous pages(fragments). 然后,我希望最后一页(第5页)显示前4个页面(片段)中所有视图的所有用户输入值。 How do I do that? 我怎么做?

I can't find any way to read the user input values from the previous fragments. 我找不到任何方法可以读取先前片段中的用户输入值。 The views may not even exist anymore(But will be recreated if the user goes back). 视图甚至可能不再存在(但如果用户返回,将重新创建视图)。

And I can't seem to get the existing fragments. 而且我似乎无法获得现有的片段。

I would consider having a custom object that keeps the data each fragment fills. 我会考虑拥有一个自定义对象,该对象保留每个片段填充的数据。 Something like: 就像是:

public class FillerData implements Parcelable {
    private String page0$data0;
    private String page0$data1;
    private String page0$data2;

    // getters and setters if you wish

    // implement Parcelable interface as this object will be managed by host activity
}

You'll have only one such object managed by parent activity and the parent activity will implement an interface for exposing this object: 您将只有一个这样的对象,该对象由父级活动管理,并且父级活动将实现用于暴露此对象的接口:

public static interface FillerDataExposer {
    public FillerData exposeFiller();
}

public class MyFragmentHostActivity extends FragmentActivity implements FillerDataExposer {
    private static final String FILLER_KEY = "FILLER_KEY";
    private FillerData myFillerData;

    protected void onCreate(Bundle savedInstance) {
        .......
        if(savedInstance != null) {
            myFillerData = (FillerData) savedInstance.getParcelable(FILLER_KEY);
        } else {
            myFillerData = new FillerData();
        }
    }

    protected void onSaveInstanceState(Bundle savedInstance) {
        super.onSaveInstanceState();
        savedInstance.putExtra(FILLER_KEY, myFillerData);
    }

    public FillerData exposeFiller() {
        return this.myFillerData;
    }
}

Now, each of your fragments will have access to that centralized data filler object through parent activity. 现在,您的每个片段都可以通过父活动访问该集中式数据填充对象。 To reduce the weight of your code, all your fragments could extend from a base fragment class that provides access to FillerDataExposer implementation (actually, the parent activity): 为了减轻代码的重量,所有片段都可以从基本片段类扩展,该基本片段类提供对FillerDataExposer实现的访问(实际上是父活动):

public abstract class AbstractFillerFragment extends Fragment {
    protected FillerDataExposer dataExposer;

    public void onAttach(Activity act) {
        super.onAttach(act);
        // make sure no ClassCastExceptions
        this.dataExposer = (FillerDataExposer) act;
    }
}

Fragments that should only record the data filled could look like this: 仅应记录填充数据的片段如下所示:

public class Page1Fragment extends AbstractFillerFragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = // inflate XML resource ...
        yourEditText = (EditText) view.findViewById(...);
        // other relevant code ....
    }

    public void onViewCreated(View view, Bundle savedInstanceState) {
       yourEditText.setText(dataExposer.exposeFiller.setPageX$DataY());
       // some code for EditText.addTextChangedListener(new TextWatcher() could look like:
        yourEditText.addTextChangedListener(new TextWatcher() {

          public void afterTextChanged(Editable s) {

            dataExposer.exposeFiller().setPage1$Data0(s.toString());

          }

          public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

          public void onTextChanged(CharSequence s, int start, int before, int count) {}
       });
    }
}

While the fragment that needs to have access to all data stored could look like this: 虽然需要访问所有存储数据的片段如下所示:

public class FinalFragment extends AbstractFillerFragment {
    public void collectAllData() {
        DataFiller allDataCollectedObject = dataExposer.exposeFiller();
        // by calling get...() you should have access to collected data.
    }
}

This only a sketch, but you'll get the picture. 这只是一个草图,但是您会得到图片的。 The idea is to keep a single object in your activity managed across activity restarts and to make it accessible through interfaces so you will respect the fragment to activity patterns. 这样做的目的是在活动重新启动期间对活动中的单个对象进行管理,并使该对象可通过接口进行访问,因此您将尊重活动模式的片段。

Hope it makes sense ... 希望有道理...

2 solutions come to my mind. 我想到2个解决方案。

The first one is to save user input data when your first 4 fragment's onpause() methods are called. 第一个是在调用前四个片段的onpause()方法时保存用户输入数据。 You may save the data to a preference and then retrieve it from your 5th fragment. 您可以将数据保存到首选项,然后从第5个片段中检索它。

The second approach is to persist your fragments while swiping.This way the swiping will be faster and cleaner and they want be recreated everytime a swipe happens: 第二种方法是在滑动时保留片段,这样可以更快更干净地滑动片段,并希望在每次滑动时都重新创建它们:

yourcustomviewpager.setOffscreenPageLimit(5);

About setOffscreenPageLimit from the android doc : 关于来自android doc的 setOffscreenPageLimit:

Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. 设置在空闲状态下视图层次结构中应保留到当前页面任一侧的页面数。 Pages beyond this limit will be recreated from the adapter when needed. 超出此限制的页面将在需要时从适配器重新创建。 This is offered as an optimization. 这是作为优化提供的。 If you know in advance the number of pages you will need to support or have lazy-loading mechanisms in place on your pages, tweaking this setting can have benefits in perceived smoothness of paging animations and interaction. 如果您事先知道需要支持的页面数或页面上具有延迟加载机制,则调整此设置可以使分页动画和交互的流畅性受益。 If you have a small number of pages (3-4) that you can keep active all at once, less time will be spent in layout for newly created view subtrees as the user pages back and forth. 如果您只有很少的页面(3-4)可以一次全部保持活动状态,则随着用户来回翻页,新创建的视图子树的布局将花费更少的时间。 You should keep this limit low, especially if your pages have complex layouts. 您应将此限制保持在较低水平,尤其是在页面布局复杂的情况下。 This setting defaults to 1. 此设置默认为1。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM