jneander
jneander

Reputation: 1190

How to Retrieve Reference to Custom View from Within Fragment

I have a custom View that I would like to use inside a Fragment. The logic around interacting with that View should reside within the Fragment (or an object owned by that fragment). In the onCreateView method of the Fragment, I inflate the fragment layout. Immediately afterward, I attempt to obtain a reference to the BadgeButton used in the layout.

The problem that I am seeing is that I cannot obtain a reference to the custom view. With the two lines commented out as shown below, the Activity will load correctly and show the BadgeButton appropriately.

When I removed the Fragment from this example and merged its layout into that of the MainActivity, it was able to obtain the reference just fine. What is the cause of this behavior?

MainActivity

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
      getFragmentManager().beginTransaction()
        .add(R.id.container, new MainFragment())
        .commit();
    }
  }
}

MainFragment

public class MainFragment extends Fragment {
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);
    // BadgeButton badger = (BadgeButton) this.getActivity().findViewById(R.id.badger);
    // badger.setBadgeText("example"); // NullPointerException
    return rootView;
  }
}

BadgeButton

public class BadgeButton extends FrameLayout {
  private TextView mBadgeTextView;

  public BadgeButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  }

  public void setBadgeText(String value) {
    mBadgeTextView.setText(value);
  }

  private void init(Context context) {
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View inflate = inflater.inflate(R.layout.badge_button, this, true);
    mBadgeTextView = (TextView) getChildAt(1);
    mBadgeTextView.setText("0");
  }
}

badge_button.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
  <Button
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="top|left"
    android:textSize="18sp"
    android:text="123"/>
</merge>

fragment_main.xml

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingBottom="@dimen/activity_vertical_margin"
  tools:context="com.example.badgebutton.MainFragment">

  <com.example.badgebutton.BadgeButton
    android:id="@+id/badger"
    android:layout_width="120dp"
    android:layout_height="120dp"/>

</LinearLayout>

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.badgebutton.MainActivity"
    tools:ignore="MergeRootFrame" />

If you have any input about the quality of this question or advice on how to improve this and future questions, please let me know (in whichever way is appropriate). I would like to ask good questions and be a valuable contributor to the community. Thank you.

Upvotes: 0

Views: 705

Answers (1)

Triode
Triode

Reputation: 11357

BadgeButton badger = (BadgeButton) rootView.findViewById(R.id.badger);
badger.setBadgeText("example");

Use this since the view is associated with the Fragment not the Activity.

Upvotes: 1

Related Questions