在ChildFragment中创建BaseFragment并扩展此Fragment

时间:2017-09-11 07:17:41

标签: android android-fragments

我不知道这是否是重复的问题,但我没有找到任何解决方案。

问题是,有一个屏幕在所有屏幕上都有类似的视图,屏幕是碎片。

所以,我想创建一个基本片段,并希望在所有子片段中扩展这个基本片段。

我在Google上找到了演示示例,但我没有找到任何解决方案。

我不知道从哪里开始。

请帮帮我。

我找到了这个链接,但不太清楚:

  1. Fragments inheritance Android

  2. When do I need a base activity and base fragment?

  3. BaseFragment.java

    public class BaseFragment extends Fragment {
    
      public BaseFragment() {
        // Required empty public constructor
      }
    
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
    
        return inflater.inflate(R.layout.fragment_base, container, false);
      }
    }
    

    ChildFragment.Java

    public class ChildFragment extends BaseFragment{
    
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_child, container, false);
      }
    }
    

    现在,fragment_child布局中有一个TextView。当我运行应用程序时显示 但是fragment_base中还有另外两个视图,它们没有显示......

    enter image description here

7 个答案:

答案 0 :(得分:7)

抽象类方法?

我理解你在这里做什么(继承)。但正如@hobokent指出的那样,仅通过继承BaseClass将不会在BaseClass Layout之上包含您的childView布局。 有很多方法可以解决这个问题

让我们来看看这个解决方案。

  • 创建一个扩展Fragment类的抽象类(This 将是BaseClass)。

  • 制作一个将返回布局的抽象方法。

  • 在ChildClass中为您的抽象方法提供实现。

以下是代码段。

  

BaseClass的

public abstract class BasicFragment extends Fragment {

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

  public View onCreateView(LayoutInflater inflater,ViewGroup parent, Bundle savedInstanseState)
   {
      View view = provideYourFragmentView(inflater,parent,savedInstanseState);
      return view;
   }

   public abstract View provideYourFragmentView(LayoutInflater inflater,ViewGroup parent, Bundle savedInstanceState);

}
  

ChildClass

public class ImageFragment extends BasicFragment{

  @Override
  public View provideYourFragmentView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.image_fragment,parent,false);

    //Now specific components here (you can initialize Buttons etc)

    return view;
   }


}

对于您的特定要求,如果您希望在子类布局中显示相同的布局。您可以创建一个返回布局的方法,也可以在子布局中为BaseClass Layout创建占位符,并使用child.add(base_layout)在childLayout中添加BaseClass布局。 这又是另一种设计方案 您还可以在Activity布局中放置一个公共布局,并在片段的Activity占位符中添加片段。 有很多可能的解决方案。

我没有任何特定于您的要求的代码,但这里是我为TabLayout实现此方法的示例,其中每个标签是不同的片段,具有不同的布局。
Github full code sample

答案 1 :(得分:1)

扩展片段不会包含视图,这些视图来自您扩展的布局,因此您无法在子片段中看到fragment_base中的文本视图。

相反,创建和使用自定义视图/复合视图可以让您受益,然后可以在其他片段中重复使用。

您可以在此处阅读化合物视图:

https://medium.com/@Sserra90/android-writing-a-compound-view-1eacbf1957fc

答案 2 :(得分:0)

BaseFragment扩展了Fragment类,然后你的其他Fragments扩展了BaseFragment

public class BaseFragment extends Fragment 

public class AboutFragment extends BaseFragment

如果你想要其他布局:

 View headView = LayoutInflater.from(getContext()).inflate(R.layout. - your Fragment layout - , null, false);

这对我有用。

希望它有所帮助。

答案 3 :(得分:0)

您可以通过为每个子片段包含基本布局来实现此目的。然后,您需要将基本片段中的视图绑定到基本布局中的所有基本视图。对于子视图布局,您需要将其绑定在子片段中。

这里的步骤:

  1. 创建基本片段布局(fragment_base.xml):

     <?xml version="1.0" encoding="utf-8"?>
       <RelativeLayout>
    
           <!-- Declare your view here -->
           <android.support.v7.widget.AppCompatTextView
               android:id="@+id/sample_tv"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="Sample"/>
    
     </RelativeLayout>
    
  2. 创建基本片段

    public class BaseFragment extends Fragment {
    
      public BaseFragment() {
        // Required empty public constructor
      }
    
      ...
    }
    
  3. 在基本片段中创建一个基本方法来绑定视图。这将被重写并在您的子片段中重用。在这里,我们使用bindView()名称:

    public class BaseFragment extends Fragment {
    
      protected AppCompatTextView mTvSample;
    
      ...
    
      protected void bindView(View view) {
        mTvSample = view.findViewById(R.id.sample_tv);
      }
      ...
    
    }
    
  4. 通过重用基本布局来创建子布局。您可以使用包含。它应该是这样的(fragment_child.xml):

     <?xml version="1.0" encoding="utf-8"?>
       <RelativeLayout>
    
           <include
                layout="@layout/fragment_base"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
           />
    
           <!-- Child view -->
           <android.support.v7.widget.AppCompatTextView
               android:id="@+id/child_tv"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="Child Sample"/>
    
     </RelativeLayout>
    
  5. 现在,您可以通过扩展基本片段来创建子片段。您需要记住使用并覆盖bindView()。所以,你需要做这样的事情:

    public class ChildFragment extends BaseFragment {
      private AppCompatTextView mTvChild;
      public ChildFragment() {
        // Required empty public constructor
    
      }
    
    
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
    
        View view = inflater.inflate(R.layout.fragment_child, container, false);
    
        bindView(view);
        return view;
      }
    
      @Ovverride
      protected void bindView(View view) {
        super.bindView(view); //call base method to bind the base view
        mTvChild = view.findViewById(R.id.child_tv);
      }
    }
    

答案 4 :(得分:0)

我已经实现了此结构,您可以在其中将BaseFragment布局显示在ChildFragment布局中。基本上,我使用ViewStub来实现该解决方案。 VewStub是一种占位符布局。它会在加载xml时创建,然后您可以用指定的视图层次结构替换ViewStub。我将使用不言自明的变量名,以避免其他说明:)。您可以在GitHub上检出sample project

  

fragment_core.xml

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

    <ViewStub
        android:id="@+id/child_fragment_will_be_displayed_here"
        android:layout_width="match_parent"
        android:layout_height="100dp">
    </ViewStub>


    <TextView
        android:id="@+id/core_fragment_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/child_fragment_content_holder"/>

</RelativeLayout>
  

FragmentCore.class

   public abstract class FragmentCore extends Fragment {

    public FragmentCore() {
        // Required empty public constructor
    }

     protected TextView mTextViewInCoreActivity;

     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         View coreFragmentView = inflater.inflate(R.layout.fragment_core, container, false);
         mTextViewInCoreActivity = coreFragmentView.findViewById(R.id.core_fragment_text_view);
         loadLayoutFromResIdToViewStub(coreFragmentView, container);
         return coreFragmentView;
     }

     public abstract void loadLayoutFromResIdToViewStub(View rootView,ViewGroup container);

 }
  

fragment_child.xml

 <FrameLayout
    android:layout_width="match_parent"
    android:layout_height="100dp"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/child_fragment_content_holder">

    <TextView
        android:id="@+id/child_fragment_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</FrameLayout>
  

FragmentChild.class

    public class FragmentChild extends FragmentCore {


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Override
    public void loadLayoutFromResIdToViewStub(View coreFragmentView, ViewGroup container){

        setRetainInstance(true);

        if (container != null) {
            container.removeAllViews();
        }

        ViewStub stub = coreFragmentView.findViewById(R.id.child_fragment_will_be_displayed_here);
        stub.setLayoutResource(R.layout.fragment_child);
        stub.inflate();

        TextView childFragmentTextView = coreFragmentView.findViewById(R.id.child_fragment_text_view);

        mTextViewInCoreActivity.setText("Core (Parent) Fragment TextView is accessible");
        childFragmentTextView.setText("Child Fragment TextView is accessible");
    }

}

答案 5 :(得分:0)

您可以这样做

<i class="far fa-envelope" class="inbox"></i>

片段

abstract class BaseFragment : Fragment() {

override fun onCreateView(inflater: LayoutInflater, container:ViewGroup?, savedInstanceState: Bundle?): View {
    return inflater.inflate(getContentView(), container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

        onViewReady(savedInstanceState, arguments)
    }
// create below 2 methods
    abstract fun getContentView(): Int // this will be used to pass view
    abstract fun onViewReady(savedInstanceState: Bundle?, bundle: Bundle?) // this will be invoked in our fragment when view is ready
}

答案 6 :(得分:0)

遵循这种简单干净的方法

public abstract class BaseFragment extends Fragment { 
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = inflater.inflate(getLayoutId(), null);

    return root;
}

@LayoutRes
protected abstract int getLayoutId();
}

就是基本片段了

然后获取子片段

public class ChildFragment extends BaseFragment {

@Override
protected int getLayoutId() {
    return R.layout.child_fragment;
}

}

采用不同的方法来处理事情