【问题标题】:How do I change the view inside a fragment?如何更改片段内的视图?
【发布时间】:2011-05-10 16:49:35
【问题描述】:

如您所料,我有一个片段可以在 onCreateView 中创建其视图。但是我想定期更改视图。

我的用例是片段显示来自 Web 服务的一些数据。当用户从列表(另一个片段)中选择一个选项时,该片段应该切换到进度条,然后在加载后切换回数据视图。

我可以制作两个片段 - 加载片段和显示片段,但似乎因为这是一个封装事件,我宁愿在一个片段中完成所有操作。

基本上我要问的是,片段内的 setContentView 的等价物是什么。

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    您可以使用Fragment.getView()。这将返回包含Fragment 的容器的视图。在该视图上,您​​可以致电removeAllViews。然后构建您的新视图并将它们添加到您从getView() 获得的视图中。

    http://developer.android.com/reference/android/app/Fragment.html#getView()

    【讨论】:

    • 这个答案在技术上是不正确的。 getView() 返回onCreateView() 中提供的View 而不是容器View
    • 好点。不过,这仍然是对@monkjack 问题的回答。
    • getView() 返回视图但没有removeAllViews() 方法。该方法似乎在ViewGroup 中。我错过了什么吗?
    • 没错。但是 View 将成为 ViewGroup 是完全可行的。不过不是很健壮。
    【解决方案2】:

    如果出于任何原因,您想要更改整个片段视图(例如,将在成功时更改视图的异步 URL 请求),您可以使用父活动中的 FragmentTransaction 并动态创建一个新片段.

    或者您可以保留该片段并调用该片段的方法,该方法将自行刷新。 例子: 在父活动中,我构建并存储了片段列表List<RefreshFragment> mFragmentList

    这是 RefreshFragment 类(在我的示例中,我所有的片段都扩展了这个):

    public class RefreshFragment extends Fragment {
        protected Data data; // here your asynchronously loaded data
    
        public void setData(Data data) {
            this.data = data;
            // The reload fragment code here !
            if (! this.isDetached()) {
                getFragmentManager().beginTransaction()
                   .detach(this)
                   .attach(this)
                   .commit();
            }
        }
    }
    

    然后在我的活动异步回调中我可以调用:

    for (RefreshFragment f : mFragmentList) f.setData(data);
    

    因此,每个片段都将使用正确的数据进行更新,并且当前附加的片段将立即自我更新。当然,您必须在片段中提供自己的 onCreateView。

    重要的是片段可以用getFragmentManager()重新加载自己。

    现在,我建议为此使用 ViewModel

    【讨论】:

    • 问题是当您加载数据或用户单击按钮时,片段永远不会分离...
    • @Waza_Be 我认为它是一种类型,应该如下所示:if (!this.isDetached()) {
    • 我相信这是解决更新片段视图问题的最佳方法。当您遵循将 Fragments 用作 Views 并将 Activity 用作 Controller 的模式时,这很棒。它非常简洁,它允许我利用继承并将所有视图逻辑收集在一个地方 - OnCreateView。我希望我不会发现这种方法有任何明显的缺点,这会让我寻找另一种方法。
    • 这应该是比我尝试过的任何其他解决方案更好的答案。谢谢你救了我的培根!
    • 我认为 Fragment 设计用于固定视图。所以我认为在这里重新创建 Fragment 对象是最合适的决定。
    【解决方案3】:

    您可以使用FrameLayout 在进度条和数据视图之间切换,例如

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <ImageView android:id="@+id/cover_image"
            android:scaleType="fitCenter"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
        <ProgressBar android:id="@+id/cover_progress"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_gravity="center"/>
    </FrameLayout>
    

    onViewCreate() 中,您可以将两个视图存储到实例字段中

    public View onCreateView(LayoutInflater inflater,
            ViewGroup container, Bundle savedInstanceState) {
        ...
        image = (ImageView) container.findViewById(R.id.cover_image);
        progress = container.findViewById(R.id.cover_progress);
        ...
    }
    

    当你想在两者之间切换时(记得在你的 UI/主线程中进行),只需执行类似的操作

    progress.setVisibility(View.INVISIBLE);
    image.setVisibility(View.VISIBLE);
    

    【讨论】:

    • ViewSwitcher这种情况也方便
    • view.findViewById(R.id.cover_image);变量“视图”是什么?
    • @Montaro 应该是 container,已在答案中修复。谢谢!
    【解决方案4】:

    创建一个“虚拟”默认视图

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
    </LinearLayout>
    

    在片段的 onCreateView 方法中膨胀“虚拟”默认视图,并将其用作占位符以根据需要添加视图

    private LayoutInflater mInflater;
    private ViewGroup mContainer;
    
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){
        mInflater = inflater;
        mContainer = container;
    
        View v =inflater.inflate(R.layout.home_view,container,false);
        placeholder = (ViewGroup) v;
    
        return placeholder;
    }
    

    要将视图更改为新视图,您首先删除所有以前的视图,然后膨胀新视图并添加

    View newView = mInflater.inflate(R.layout.custom_dash, mContainer, false);
    placeholder.removeAllViews();
    placeholder.addView(newView);
    

    【讨论】:

      【解决方案5】:

      这里有一个更简单的解决方案:将您收到的充气机和容器保存在 onCreateView 中,稍后再使用。例如:

      private LayoutInflater mInflater;
      private ViewGroup mRootView;
      
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          mInflater = inflater;
          mRootView = container;
          return null;
      }
      
      public void someCallBackLater() {
          // mRootView.removeAllViews();   // in case you call this callback again...
          mInflater.inflate(R.layout.my_layout, mRootView);
      }
      

      【讨论】:

      【解决方案6】:

      你可以使用事务删除和添加。我使用了一个片段,我可以在其中加载任何视图。 Fragment 的构造函数必须有一个整数,该整数是 R.layout.... 我只是删除旧片段并放入一些新片段。 !!!仅当您将此片段设为动态且不在 xml 布局中时,它才有效。 只需创建类似 LinearLayout R.id.fragment_layout 的东西

      @Override
      protected void onCreate(Bundle savedInstanceState) {
      
          super.onCreate(savedInstanceState);
      
          setContentView(R.layout.wundlist_fragmente);
          Log.v("WoundListActivity", "WoundListActivity gestartet...");
      
          Log.v("WoundListActivity", "Liste...");
          //dynamisch hinzufügen...
          wlf=new WoundListFragment();        
          fm.beginTransaction().add(R.id.fragment_layout,wlf).commit();
      
      }
      
      //If Menubutton Clicked change
      
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          if(item.getItemId()==R.id.itemaddwound){
              Log.v("List", "neue Wunde Activity");
      
              fm.beginTransaction().remove(wlf).commit();
              fm.beginTransaction().add(R.id.fragment_layout, new NewWoundFragment()).commit();
      
          }
      
          return super.onOptionsItemSelected(item);
      }
      

      【讨论】:

        【解决方案7】:

        使用 Solostaran14 的响应,我现在正在这样做:

        界面:

        public interface FragmentReattachListener {
        
            public void reAttach();
        
        }
        

        片段:

        public class MyFragment extends Fragment implements  FragmentReattachListener {
        //...
        
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            //...
            App.registerFragmentReattachListener(this);
            //...
        }
        
        //...    
        
        @Override
        public void reAttach() {
            FragmentManager f = getFragmentManager();
            if (f != null) {
                 f.beginTransaction()
                            .detach(this)
                            .attach(this)
                            .commit();
                }
            }
        
        }
        

        来自应用程序类:

        private static void reattachFragments() {
                if (fragmentReattachListeners.size() > 0) {
                    for (FragmentReattachListener listener : fragmentReattachListeners) {
                        listener.reAttach();
                    }
                }
            }
        

        【讨论】:

        • 我赞成:更好的界面。
        【解决方案8】:

        这对我有用:

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View v = inflater.inflate(R.layout.fragment_recipe, container, false);
            Button recipeBuyButton = (Button) v.findViewById(
                    R.id.recipe_buy_button);
            Typeface tf = Typeface.createFromAsset(getActivity().getAssets(), "fonts/GE_SS_Two_Medium.otf");
            recipeBuyButton.setTypeface(tf);
            return v;
        

        【讨论】:

        • 为什么人们对正确答案投反对票?这个答案没有错。从我这边 +1。
        • 因为这个答案与当前问题无关。
        【解决方案9】:

        我有同样的问题,fragment.getView() 总是返回 null,虽然之前已经调用过 Fragment.onCreateView

        我们无法在运行时更改片段的内容,因为我的片段已添加到 ViewPager,所以我尝试使用其他方法来获取视图:

         View view  =  viewPager.getChildAt(0);
         TextView text = (TextView) (view.findViewById(R.id.textView));
         text.setText("12345");
        

        这个问题已经解决了,希望能帮到你

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多