【问题标题】:findViewById in Fragment片段中的 findViewById
【发布时间】:2017-10-02 04:16:10
【问题描述】:

我正在尝试在 Fragment 中创建一个 ImageView,它将引用我在 XML 中为 Fragment 创建的 ImageView 元素。但是,findViewById 方法仅在我扩展 Activity 类时才有效。无论如何,我也可以在 Fragment 中使用它吗?

public class TestClass extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ImageView imageView = (ImageView)findViewById(R.id.my_image);
        return inflater.inflate(R.layout.testclassfragment, container, false);
    }
}

findViewById 方法上有一个错误,指出该方法未定义。

【问题讨论】:

  • 使用 Android 的 ButterKnife 视图绑定库。还要演示它是如何工作的,如何在您的 android 应用开发中集成和使用,以使您的开发更快。
  • '一些'时间过去了,但您仍然没有接受答案。您能否选择对您最有帮助的答案,以便将其标记为已回答?
  • 鼓励使用数据绑定 orang 视图绑定代替手动 findViewById

标签: android android-fragments android-imageview findviewbyid


【解决方案1】:

使用getView() 或来自实现onViewCreated 方法的View 参数。它返回片段的根视图(onCreateView() 方法返回的那个)。有了这个你可以打电话给findViewById()

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    ImageView imageView = (ImageView) getView().findViewById(R.id.foo);
    // or  (ImageView) view.findViewById(R.id.foo); 

由于getView() 仅在onCreateView() 之后有效,您不能在片段的onCreate()onCreateView() 方法中使用它

【讨论】:

  • 注意:只有在 onCreateView() 之后才有效。所以,你不能在 onCreate() 中使用它
  • 如果 onCreate 不是正确的地方,我可以重写什么函数来实现这个?
  • 如果 ImageView 来自膨胀的布局,这将无济于事 - 有关详细信息,请参阅我的答案。否则,onCreateView 是执行此操作的正确位置@N-AccessDev
  • 最好的地方是 onViewCreated 方法
  • 文档指出onActivityCreated() 是推荐的位置来查找和存储对您的视图的引用。您必须通过在onDestroyView() 中将它们设置回null 来清理这些存储的引用,否则您将泄漏Activity
【解决方案2】:

您需要扩充 Fragment 的视图并在它返回的 View 上调用 findViewById()

public View onCreateView(LayoutInflater inflater, 
                         ViewGroup container, 
                         Bundle savedInstanceState) {
     View view = inflater.inflate(R.layout.testclassfragment, container, false);
     ImageView imageView = (ImageView) view.findViewById(R.id.my_image);
     return view;
}

【讨论】:

  • 当您执行 V.findViewById(R.id.someid) 时,肯定只适用于膨胀视图中的所有小部件。如果他试图膨胀的 imageView 在膨胀的视图之外怎么办?
  • 那么“拥有”并膨胀 imageView 的类需要提供对它的公共访问。这是非常糟糕的做法。片段应该只能访问其布局中存在的 UI 元素。
  • 看起来你的代码有问题(从后台线程更新 UI),不是我的。
  • 谢谢,很有用。作为不相关的评论:尝试在代码中坚持 Java 命名约定。 "V" 看起来不像 Java 中的变量名。
  • 这应该是正确的答案。被接受的会留下NullPointerException
【解决方案3】:

Fragment 类中,您将获得onViewCreated() 覆盖方法,您应该始终初始化您的视图,因为在此方法中您可以获得视图对象,您可以使用它找到您的视图,例如:

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    view.findViewById(R.id.yourId).setOnClickListener(this);

    // or
    getActivity().findViewById(R.id.yourId).setOnClickListener(this);
}

始终记住,如果您从 onCreateView() 方法返回 null 或 super.onCreateView(),则在 Fragment 的情况下不会自动调用 onViewCreated() 方法。 在ListFragment的情况下默认调用它,因为ListFragment默认返回FrameLayout

注意:一旦onCreateView() 成功执行,您可以使用getView() 在类中的任何位置获取片段视图。 即

getView().findViewById("your view id");

【讨论】:

  • 我很惊讶没有多少人支持这个响应——这是在片段上设置监听器的正确方法......也许这是 API 的新发展。
  • 使用view 传递给onViewCreated 仍然会导致NullPointerException 但使用getActivity() 很好。任何想法为什么?
  • @dVaffection 可能是您在片段的 onCreateView() 生命周期方法中没有返回非空视图。现在,在 getActivity 的情况下,您从活动中获取视图而不是片段主视图取决于您传递的 id。请检查您是否从 onCreateView 返回非空视图?然后告诉我。
  • @AnkurChaudhary 我从onCreateView 方法返回视图。我刚刚调试过,结果发现有一个布局(在我的例子中是FrameLayout)。话虽如此,当我尝试找到一个元素时,它会返回null。为什么会这样?
  • @dVaffection 能否分享一下你的片段类和相应的布局。
【解决方案4】:

我知道这是一个老问题,但普遍的答案还有待改进。

这个问题不清楚imageView 的要求是什么——我们是把它作为视图传回去,还是只是保存一个参考供以后使用?

无论哪种方式,如果 ImageView 来自膨胀布局,那么正确的做法是:

public class TestClass extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.testclassfragment, container, false);
        ImageView imageView = (ImageView)v.findViewById(R.id.my_image);
        return v;
    }
}

【讨论】:

  • 那么你将如何从 ListFragment 更新 imageView?这需要 FragmentManager 吗?换句话说,如何从单独的类的 onListItemClick 更新详细片段中的 imageView?
  • 您可以在方便的地方保存对 imageView 的引用,或者在需要时保存 fragment.getView().findViewById(R.id.my_image)。在 ListFragment 中,假设图像位于列表项中,您通常会在适配器的 getView 方法中使用列表视图项的 setTag/getTag 方法创建一个引用持有者 - 有很多示例说明如何执行此操作。
  • @MattJenko,您能否分享更多详细信息或示例在使用膨胀布局时如何获得有效的解决方案?例如,我有一个带有 tablayout(4 个选项卡)的 viewpager2,并且我正在扩展片段中的 edittext 视图,并且我需要从主要活动中访问每个 viewpager2 视图的 editext。具体怎么做?
【解决方案5】:

首先获取片段视图,然后从该视图获取您的 ImageView。

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.testclassfragment, container, false);
    ImageView imageView = (ImageView) view.findViewById(R.id.my_image);
    return view;
}

【讨论】:

  • 那么,onCreate 方法在 Fragment 中有用吗?
  • onCreateView 创建并返回与片段关联的视图层次结构。调用onCreate 来执行片段的初始创建。实际上,这取决于您在这些方法中编写的内容。
  • 好的,但是如何在 onCreate 中声明变量?因为 View 在 onCreateView 方法里面。
  • @Tsunaze 你有没有从 onCreate 方法中发现如何做到这一点?
  • 我同意。这个答案应该被标记为解决方案。
【解决方案6】:

您也可以在onActivityCreated 方法中执行此操作。

public void onActivityCreated(Bundle savedInstanceState) { 
      super.onActivityCreated(savedInstanceState);
}

就像他们在这里做的那样:http://developer.android.com/reference/android/app/Fragment.html (在 API 级别 28 中已弃用)

getView().findViewById(R.id.foo);

getActivity().findViewById(R.id.foo);

有可能。

【讨论】:

  • 请注意,API 28 引入了 requiereActivity()、requireView()、requireViewById()。
【解决方案7】:

Fragment 类中,我们得到 onViewCreated() 覆盖方法,我们应该始终初始化我们的视图,因为在这个方法中我们得到 view 对象。使用这个对象,我们可以找到如下视图:

class MyFragment extends Fragment {
    private ImageView imageView;

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

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //initialize your view here for use view.findViewById("your view id")
        imageView = (ImageView) view.findViewById(R.id.my_image);
    }
}

【讨论】:

    【解决方案8】:

    getView() 将给出根视图

    View v = getView().findViewByID(R.id.x); 
    

    【讨论】:

      【解决方案9】:

      您可以覆盖 onViewCreated(),它在所有视图都被膨胀后立即调用。这是填写 Fragment 成员 View 变量的正确位置。这是一个例子:

      class GalleryFragment extends Fragment {
          private Gallery gallery;
      
          (...)
      
          @Override
          public void onViewCreated(View view, Bundle savedInstanceState) {
              gallery = (Gallery) view.findViewById(R.id.gallery);
              gallery.setAdapter(adapter);
              super.onViewCreated(view, savedInstanceState);
          }
      }
      

      【讨论】:

        【解决方案10】:

        方法 getView() 不适用于 OnCreate 和类似方法之外的片段。

        您有两种方法,将视图传递给 oncreate 上的函数(这意味着您只能在创建视图时运行您的函数)或将视图设置为变量:

        private View rootView;
        
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
            rootView = inflater.inflate(R.layout.fragment_contatos, container, false);
        }
        
        public void doSomething () {
            ImageView thumbnail = (ImageView) rootView.findViewById(R.id.someId);
        }
        

        【讨论】:

          【解决方案11】:

          1) 首先对 Fragment 进行膨胀布局,然后您可以使用 findviewbyId 。

          View view = inflater.inflate(R.layout.testclassfragment, container, false);
                       ImageView imageView = (ImageView) view.findViewById(R.id.my_image);
                       return view;
          

          【讨论】:

            【解决方案12】:

            同意在视图上调用findViewById()

            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                View V = inflater.inflate(R.layout.testclassfragment, container, false);
                ImageView imageView = (ImageView) V.findViewById(R.id.my_image);
            
                return V;
            }
            

            【讨论】:

              【解决方案13】:
              EditText name = (EditText) getView().findViewById(R.id.editText1);
              EditText add = (EditText) getView().findViewById(R.id.editText2);  
              

              【讨论】:

                【解决方案14】:

                注意:

                从 API 级别 26 开始,您也不需要专门转换 findViewById 的结果,因为它使用推断作为其返回类型。

                所以现在你可以简单地做,

                public View onCreateView(LayoutInflater inflater, 
                                         ViewGroup container, 
                                         Bundle savedInstanceState) {
                     View view = inflater.inflate(R.layout.testclassfragment, container, false);
                     ImageView imageView =  view.findViewById(R.id.my_image); //without casting the return type
                     return view;
                }
                

                【讨论】:

                • 没有铸造的事情解释对我有帮助。
                • 我建议将此答案与 API 28 中提到弃用 getView() 结合起来。
                【解决方案15】:

                使用

                imagebutton = (ImageButton) getActivity().findViewById(R.id.imagebutton1);
                
                imageview = (ImageView) getActivity().findViewById(R.id.imageview1);
                

                会有用的

                【讨论】:

                  【解决方案16】:

                  根据 API 级别 11 的文档

                  参考,在后台堆栈中 http://developer.android.com/reference/android/app/Fragment.html

                  短代码

                  /**
                   * The Fragment's UI is just a simple text view showing its
                   * instance number.
                   */
                  @Override
                  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                          Bundle savedInstanceState) {
                      View v = inflater.inflate(R.layout.hello_world, container, false);
                      View tv = v.findViewById(R.id.text);
                      ((TextView)tv).setText("Fragment #" + mNum);
                      tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
                      return v;
                  }
                  

                  【讨论】:

                    【解决方案17】:

                    使用getView()返回fragment的view,然后你可以调用findViewById()访问fragment view中的任意view元素。

                    【讨论】:

                    • 视图不是活动
                    【解决方案18】:

                    试试这个对我有用

                    public class TestClass extends Fragment {
                        private ImageView imageView;
                    
                        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                            View view = inflater.inflate(R.layout.testclassfragment, container, false);
                            findViews(view);
                            return view;
                        }
                    
                        private void findViews(View view) {
                            imageView = (ImageView) view.findViewById(R.id.my_image);
                        }
                    }
                    

                    【讨论】:

                    • 是的,这段代码这里没问题。您对另一个的修改不是。
                    • @cricket_007 好的,你能看到我吗?
                    • 很抱歉我听不懂你的英语,但现在一切都已解决。我没有什么可以给你看的。
                    【解决方案19】:

                    最好的实现方式如下:

                    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                    
                    rootView = inflater.inflate(R.layout.testclassfragment, container, false);
                            ImageView imageView = (ImageView) rootView.findViewById(R.id.my_image);
                            return rootView
                    }
                    

                    这样,xml布局中定义的每一个控件都可以使用rootView,这样代码就干净多了。

                    希望这会有所帮助:)

                    【讨论】:

                    • 我认为这可能是可行的,但是,它不起作用
                    【解决方案20】:

                    1) 声明你的布局文件。

                    public View onCreateView(LayoutInflater inflater,ViewGroup container, 
                                                     Bundle savedInstanceState) {
                        return inflate(R.layout.myfragment, container, false);
                    }
                    

                    2)然后,获取视图的 id

                    @Override
                    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
                        super.onViewCreated(view, savedInstanceState);
                        TextView nameView = (TextView) view.findViewById(R.id.textview1);
                    }
                    

                    【讨论】:

                      【解决方案21】:

                      使用 gradle skeleton plugin,它会自动根据你的布局参考生成视图持有者类。

                      public class TestClass extends Fragment {
                          public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                              MyLayout myLayout = new MyLayout(inflater, container, false);
                              myLayout.myImage.setImageResource(R.drawable.myImage);
                              return myLayout.view;
                          }
                      }
                      

                      现在假设您在 my_layout.xml 文件中声明了一个 ImageView,它会自动为您生成 myLayout 类。

                      【讨论】:

                        【解决方案22】:

                        试试这个:

                        View v = inflater.inflate(R.layout.testclassfragment, container, false);
                        ImageView img = (ImageView) v.findViewById(R.id.my_image);
                        
                        return v;
                        

                        【讨论】:

                          【解决方案23】:

                          试试

                          private View myFragmentView;
                          
                          @Override
                          public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
                          {
                          myFragmentView = inflater.inflate(R.layout.myLayoutId, container, false);
                          myView = myFragmentView.findViewById(R.id.myIdTag)
                          return myFragmentView;
                          }
                          

                          【讨论】:

                          • 该字段没有理由。以后可以随时拨打getView()
                          【解决方案24】:

                          您可以使用您在 Fragment 中的 public void onAttach(Activity activity) 方法中获得的 Activity 对象 调用 findViewById()

                          将 Activity 保存到变量中,例如:

                          片段类中: private Activity mainActivity;onAttach() 方法中: this.mainActivity=activity;

                          最后通过变量执行每一个 findViewById : mainActivity.findViewById(R.id.TextView);

                          【讨论】:

                            【解决方案25】:

                            还有一种方法叫做 onViewCreated。

                            @Override
                            public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
                                super.onViewCreated(view, savedInstanceState);
                                ImageView imageView = (ImageView) view.findViewById(R.id.imageview1);
                            }
                            

                            【讨论】:

                              【解决方案26】:

                              我喜欢一切都井井有条。你可以这样做。

                              首先初始化视图

                              private ImageView imageView;
                              

                              然后覆盖 OnViewCreated

                              @Override
                                  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
                                      super.onViewCreated(view, savedInstanceState);
                                      findViews(view);
                                  }
                              

                              然后添加一个void方法来查找视图

                              private void findViews(View v) {
                                  imageView = v.findViewById(R.id.img);
                              }
                              

                              【讨论】:

                                【解决方案27】:

                                onCreateView 方法内部

                                1) 首先,您必须为要添加的布局/视图充气 例如。线性布局

                                LinearLayout ll = inflater.inflate(R.layout.testclassfragment, container, false);
                                

                                2) 然后你可以从布局中找到你的 imageView id

                                ImageView imageView = (ImageView)ll.findViewById(R.id.my_image);
                                

                                3)返回膨胀的布局

                                return ll;
                                

                                【讨论】:

                                • 这与 LeffelMania 的回答相同。
                                【解决方案28】:

                                你必须给视图充气

                                public class TestClass extends Fragment {
                                
                                public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                                    View v = inflater.inflate(R.layout.testclassfragment, container, false);
                                    ImageView imageView = (ImageView)v.findViewById(R.id.my_image);
                                    return v
                                }}
                                

                                【讨论】:

                                  【解决方案29】:

                                  在片段中,我们需要该窗口的视图,以便我们创建此片段的 onCreateView。

                                  然后获取视图并使用它来访问该视图元素的每个视图 id..

                                    class Demo extends Fragment
                                      {
                                          @Override
                                          public View onCreateView(final LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState)
                                          {
                                              View view =inflater.inflate(R.layout.demo_fragment, container,false);
                                              ImageView imageview=(ImageView)view.findViewById(R.id.imageview1);
                                  
                                              return view;
                                          }
                                      }
                                  

                                  【讨论】:

                                  • 1) 这对其他答案有什么影响? 2) 你好像回答了两次
                                  【解决方案30】:

                                  布局充气机在这里出现。 Layout inflater 是一个使我们能够在 java 代码中使用 XML 视图的类。因此,您可以使用以下代码扩展变量 v 中的根 xml 视图。然后使用v,可以找到根视图v的子视图。

                                  public class TestClass extends Fragment {
                                      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                                      View v = inflater.inflate(R.layout.testclassfragment, container, false);
                                      ImageView imageView = (ImageView)v.findViewById(R.id.my_image);
                                      return v;
                                      }
                                  }
                                  

                                  【讨论】:

                                    猜你喜欢
                                    • 1970-01-01
                                    • 2016-12-19
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2019-05-03
                                    • 2014-04-30
                                    • 2014-12-23
                                    相关资源
                                    最近更新 更多