Android 怎么将fragment 动态地添加到布局中的任意位置?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 怎么将fragment 动态地添加到布局中的任意位置?相关的知识,希望对你有一定的参考价值。

android 怎么将fragment 动态地添加到布局中的任意位置而不受布局文件的限制?

我们通常是用
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_view, fragment).commit();
来添加fragment到指定的视图位置。所以你的需求只需你动态的改变需要替换的这个view的位置就好了,替换流程还是不变的。
动态的改变view的位置,这需要你在java代码里动态的设置view的位置。追问

恩 这个方案应该可以,改变Fragment容器的位置应该是可以的

参考技术A 好像不能这样做。必须要指定容器的id。

如何动态地使这个子 Fragment 的 TextView 可见/不可见?

【中文标题】如何动态地使这个子 Fragment 的 TextView 可见/不可见?【英文标题】:How do I dynamically make this child Fragment's TextView visible/invisible? 【发布时间】:2016-08-29 06:22:56 【问题描述】:

我有一个包含父 Fragment 的主 Activity,而父 Fragment 又包含一个子 Fragment。我正在尝试使子 Fragment 中的 TextView 动态可见/不可见。

activity_main.xml

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

    <TextView
        android:layout_
        android:layout_
        android:text="This text belongs to the Activity"
        android:id="@+id/textView"/>

    <FrameLayout
        android:id="@+id/parent_container"
        android:layout_
        android:layout_ />

</LinearLayout>

fragment_parent.xml

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


    <TextView
        android:layout_
        android:layout_
        android:text="This text belongs to the parent fragment"
        android:id="@+id/textView"/>


    <FrameLayout
        android:id="@+id/child_container"
        android:layout_
        android:layout_ />

</LinearLayout>

fragment_child.xml

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

    <TextView
        android:layout_
        android:layout_
        android:text="This text belongs to the child fragment"
        android:id="@+id/textView"/>

    <TextView
        android:layout_
        android:layout_
        android:text="But make this text visible dynamically!"
        android:id="@+id/make_this_text_visible"
        android:visibility="invisible"/>
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity 
    public static final String PARENT_TAG = "parent_tag";
    private ParentFragment mParentFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) 
            mParentFragment = ParentFragment.newInstance();
            getSupportFragmentManager().beginTransaction().replace(R.id.parent_container, mParentFragment, PARENT_TAG).commit();
        
        else 
            mParentFragment = (ParentFragment) getSupportFragmentManager().findFragmentByTag(PARENT_TAG);
        
    

ParentFragment.java

public class ParentFragment extends Fragment 
    public static final String CHILD_TAG = "child_tag";
    private ChildFragment mChildFragment;
    private List<Integer> mList;

    public static ParentFragment newInstance() 

        Bundle args = new Bundle();

        ParentFragment fragment = new ParentFragment();
        fragment.setArguments(args);
        return fragment;
    

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment_parent, container, false);
        mList = new ArrayList<Integer>();

        if (savedInstanceState == null) 
            mChildFragment = ChildFragment.newInstance();
            getChildFragmentManager().beginTransaction().replace(R.id.child_container, mChildFragment, CHILD_TAG).commit();
        
        else 
            mChildFragment = (ChildFragment) getChildFragmentManager().findFragmentByTag(CHILD_TAG);
        
        getChildFragmentManager().executePendingTransactions(); //doesn't seem to do anything!
        doStuff();

        return view;
    

    void doStuff() 
        mList.add(4); //pretend this is actually querying a database.
        //for simplicity it just receives a single 4.

        if (mList.size() > 0)  //the list is not empty, display the text!
            mChildFragment.setTextVisible(); //error! the textivew of the child fragment is null right now
        
        else 
            mChildFragment.setTextInvisible(); //error! the textivew of the child fragment is null right now
        
    

ChildFragment.java

public class ChildFragment extends Fragment 
    private TextView mTextView;

    public static ChildFragment newInstance() 

        Bundle args = new Bundle();

        ChildFragment fragment = new ChildFragment();
        fragment.setArguments(args);
        return fragment;
    

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment_child, container, false);
        mTextView = (TextView) view.findViewById(R.id.make_this_text_visible);
        return view;
    

    public void setTextVisible() 
        mTextView.setVisibility(View.VISIBLE);
    
    public void setTextInvisible() 
        mTextView.setVisibility(View.INVISIBLE);
    

如何确保子片段在我在 ParentFragment 中调用 doStuff() 时形成?

【问题讨论】:

制作回调接口,在子fragment中实现,由父调用 like public interface Foo public void onPerform(Textview v); 下面的答案就像我想回答的一样。我在远程所以无法输入完整的代码.. :( 抱歉 【参考方案1】:

我要做的是保持文本视图可见性的状态,以便在视图创建后可以正确更新(如果尚未创建)。而不是 setTextVisible()setTextInvisible 的单独方法有一个单独的方法 setTextVisibile(boolean isVisible) 并按如下方式实现:

public class ChildFragment extends Fragment 
    private TextView mTextView;
    private boolean mIsTextVisible;

    public static ChildFragment newInstance() 
        Bundle args = new Bundle();
        ChildFragment fragment = new ChildFragment();
        fragment.setArguments(args);
        return fragment;
    

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment_child, container, false);
        mTextView = (TextView) view.findViewById(R.id.make_this_text_visible);
        setTextVisible(mIsTextVisible);

        return view;
    

    public void setTextVisible(boolean isVisible) 
        mIsTextVisible = isVisible;
        if(mTextView != null) 
            mTextView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
        
    

然后在父片段中您可以调用doStuff() 而不必担心ChildFragment 中视图的当前状态,因为mIsTextVisible 已正确设置。如果在调用setTextVisible()mTextView 为空,则可见性仍将在onCreateView() 中正确设置。

在重新创建片段(例如旋转设备时)时,请注意保存和恢复 mIsTextVisible 标志。


使用回调的替代答案

使用回调更新ParentFragment 来实现 ChildFragment.OnViewCreatedListener 及其方法。

public class ParentFragment extends Fragment
    implements ChildFragment.OnViewCreatedListener 

    @Override
    public void onViewCreated() 
        doStuff();
    

然后在ChildFragment

public class ChildFragment extends Fragment 
    public interface OnViewCreatedListener 
        void onViewCreated();
    

    public View onCreateView(LayoutInflater inflater,
        @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 

        View view = inflater.inflate(R.layout.fragment_child, container, false);
        mTextView = (TextView) view.findViewById(R.id.make_this_text_visible);

        if(getParentFragment() instanceof OnViewCreatedListener) 
            ((OnViewCreatedListener) getParentFragment()).onViewCreated();
         else if (getActivity() instanceof OnViewCreatedListener) 
            ((OnViewCreatedListener) getActivity()).onViewCreated();
        

        return view;
    

【讨论】:

假设有父片段,有没有办法在没有 ChildFragment 的情况下做到这一点?即 MainActivity 可能是 ChildFragment 的父级等。换句话说,它可以先与 Activity 通信,然后再与 ParentFragment 通信吗? 给我一分钟,因为我也在用我将使用的解决方案而不是回调来更新它。 我还更新了答案以展示如何使回调方法同时适用于活动和片段。基本上你也只是看看activity是否也实现了回调接口。 有什么理由你更喜欢第一种方法而不是回调方法? 那是个人喜好。逻辑对我来说似乎更简单,不必等待回调方法来处理Fragment

以上是关于Android 怎么将fragment 动态地添加到布局中的任意位置?的主要内容,如果未能解决你的问题,请参考以下文章

动态添加Fragment

Android学习路线(二十)运用Fragment构建动态UI

Android开发笔记(10)——使用Fragment传递

Android Fragment碎片

Android Fragment的使用

Android Fragment使用 基础篇 温故知新