我如何动态地使这个子 Fragment 的 TextView visible/invisible?

How do I dynamically make this child Fragment's TextView visible/invisible?

我有一个包含父片段的主 Activity,父片段又包含子片段。我正在尝试在子片段 visible/invisible 中动态创建一个 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_width="match_parent"
              android:layout_height="match_parent">

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

    <FrameLayout
        android:id="@+id/parent_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</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_width="match_parent"
              android:layout_height="match_parent">


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


    <FrameLayout
        android:id="@+id/child_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</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_width="match_parent"
              android:layout_height="match_parent">

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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() 时子片段已形成?

我要做的是保持文本视图可见性的状态,以便在创建视图后可以正确更新它(如果尚未创建的话)。 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;
    }
}