Reputation: 2074
I have a main Activity containing a parent Fragment, which in turn contains a child Fragment. I am trying to make a TextView in the child Fragment visible/invisible dynamically.
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);
}
}
How can I ensure that the child fragment is formed by the time I call doStuff() in the ParentFragment?
Upvotes: 2
Views: 912
Reputation: 11913
What I would do is keep the state of the text view visibility so it can be updated properly once the view has been created if it hasn't been already. Instead of separate methods for setTextVisible()
and setTextInvisible
have a single method setTextVisibile(boolean isVisible)
and implement it as follows:
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);
}
}
}
and then in the parent fragment you can call doStuff()
without worrying about the current state of the views in the ChildFragment
since mIsTextVisible
is properly set. If the mTextView
is null at the time setTextVisible()
is called the visibility will still be properly set in onCreateView()
.
Just take care to save and restore the mIsTextVisible
flag when the fragment is recreated such as when the device is rotated.
Using callbacks update the ParentFragment
to implement
ChildFragment.OnViewCreatedListener
and its method.
public class ParentFragment extends Fragment
implements ChildFragment.OnViewCreatedListener {
@Override
public void onViewCreated() {
doStuff();
}
}
And then in 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;
}
}
Upvotes: 3