【问题标题】:Fragments and ViewPager in AndroidAndroid 中的 Fragments 和 ViewPager
【发布时间】:2013-07-30 13:30:14
【问题描述】:

我有一个 ViewPager 允许用户在 5 个不同的视图之间滑动,其中每个“视图”都扩展了 Fragment。

我有自己的适配器,它扩展了 FragmentPagerAdapter 并将 getItem() 实现为

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

这很好用,用户可以在 5 个不同的视图之间滑动。但是问题来了:前 4 个视图中的每一个都包含用户可以与之交互的 Button 和 EditText 等视图。

然后我希望最后一页(第 5 页)显示来自前 4 个页面(片段)的所有视图的所有用户输入值。我怎么做?

我找不到任何方法从之前的片段中读取用户输入值。视图甚至可能不再存在(但如果用户返回,则会重新创建)。

而且我似乎无法获取现有的片段。

【问题讨论】:

  • 但我无法获得前 4 页的片段。它们甚至可能不存在。

标签: java android android-viewpager fragment


【解决方案1】:

我会考虑使用一个自定义对象来保存每个片段填充的数据。比如:

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
}

您将只有一个这样的对象由父 Activity 管理,并且父 Activity 将实现一个接口来公开该对象:

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

现在,您的每个片段都可以通过父活动访问该集中式数据填充对象。为了减少代码的重量,您的所有片段都可以从提供对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;
    }
}

应该只记录填充数据的片段可能如下所示:

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

虽然需要访问所有存储数据的片段可能如下所示:

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

这只是一个草图,但你会得到图片。这个想法是在活动重新启动时管理活动中的单个对象,并使其可以通过接口访问,这样你就会尊重活动模式的片段。

希望这是有道理的......

【讨论】:

  • 问题是和onpause一样,当我查看最后一个片段时,不会为所有片段调用onSaveInstanceState(Bundle savedInstance)。
  • 你不需要关心onpause。无论您做什么,数据始终可用。
  • 要补充一点:对于每个片段,您需要为 DataFiller 中已有的数据设置 edittext 或其他视图。这可以在 onViewCreated 中完成。
  • 我已经编辑了Page1Fragment 示例的答案,以反映上述评论。希望它更有意义......
【解决方案2】:

我想到了 2 个解决方案。

第一个是在调用前 4 个片段的 onpause() 方法时保存用户输入数据。您可以将数据保存到首选项中,然后从您的第 5 个片段中检索它。

第二种方法是在刷卡时保留您的片段。这样刷卡将更快更干净,并且每次刷卡时都希望重新创建它们:

yourcustomviewpager.setOffscreenPageLimit(5);

关于the android doc的setOffscreenPageLimit:

设置在空闲状态下视图层次结构中当前页面任一侧应保留的页面数。超出此限制的页面将在需要时从适配器重新创建。 这是作为优化提供的。如果您事先知道需要支持的页面数量或在页面上设置了延迟加载机制,则调整此设置可以提高分页动画和交互的感知流畅度。如果您有少量页面 (3-4) 可以一次保持活动状态,则在用户页面来回切换时,新创建的视图子树的布局将花费更少的时间。 您应该将此限制保持在较低水平,尤其是在您的页面具有复杂布局的情况下。此设置默认为 1。

【讨论】:

  • onpaused 技巧不起作用,因为在查看第 4 页(最后一页)时,第 3 页没有调用 onpause。
  • 你是对的。因此,您可以在每次更改输入时保存输入(您应该为您的文本视图设置侦听器)。
  • 大坝,那是很多代码。我真正需要的只是一个 fragmentNotVisibleAnymore() 方法。我想我会尝试使用一个 setOnPageChangeListener,然后它可以在每个片段中调用一个方法来收集所有数据。
  • 第二种方法只有一行代码,不需要将数据保存到偏好中,也使滑动更流畅。无论如何,这是你的电话。做你认为最好的方式:)
  • 几乎是真的,但是第二种方法需要多 4 行代码,因为它还需要我缓存我在适配器中创建的对象,以便我可以再次获取它们。但我想这是最好的解决方案,即使你这样做似乎是错误的。如果没有更好的结果,我会接受你的回答,但仍然感觉不对。
猜你喜欢
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
相关资源
最近更新 更多