Using ButterKnife library with 2 different views in 1 fragment
Asked Answered
A

1

5

I'm currently trying to use the ButterKnife library for Android to handle some boilerplate code (https://github.com/JakeWharton/butterknife)

I've got it set up, and got it semi-working, but i've run into a problem i can't fix :/

I have a Fragment which contains 1 single ListView element, and to this ListView i'm attaching a footer view which contains several elements.

This is a code snippet from my fragment using the library:

public class UsersFragment extends Fragment {
    @InjectView(R.id.users_listview_id) AutoUpdatingListView list;

    private View footerView;
    @InjectView(R.id.add_user_footer_firstname_edittext_id) BootstrapEditText firstnameEditText;
    @InjectView(R.id.add_user_footer_middlename_edittext_id) BootstrapEditText middlenameEditText;
    @InjectView(R.id.add_user_footer_lastname_edittext_id) BootstrapEditText lastnameEditText;
    @InjectView(R.id.add_user_footer_cancel_button_id) BootstrapButton cancelButton;
    @InjectView(R.id.add_user_footer_okay_button_id) BootstrapButton okayButton;
    @InjectView(R.id.add_user_footer_facebook_button) BootstrapCircleThumbnail facebookButton;
    @InjectView(R.id.add_user_footer_google_plus_button) BootstrapCircleThumbnail googlePlusButton;
    @InjectView(R.id.add_user_footer_twitter_button) BootstrapCircleThumbnail twitterButton;
    @InjectView(R.id.add_user_footer_linkedin_button) BootstrapCircleThumbnail linkedInButton;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.user_fragment, container, false);
    footerView = ((LayoutInflater) getActivity().getSystemService(Activity.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.add_user_footer_view, null, false);

    ButterKnife.inject(this, rootView);

    list.setAdapter(adapter);
    }
}

The above code does NOT work, as i can only inject with 1 view, and if i try with both of them (2x inject's), the second inject overrides the first one, leaving me with null values.

I can't seem to specify which view contains which elements like i can with the regular findViewById().

To clarify, this is my non-ButterKnife code (which works 100%):

    list = (AutoUpdatingListView) rootView.findViewById(R.id.users_listview_id);
    firstnameEditText = (BootstrapEditText) footerView.findViewById(R.id.add_user_footer_firstname_edittext_id);
    middlenameEditText = (BootstrapEditText) footerView.findViewById(R.id.add_user_footer_middlename_edittext_id);
    lastnameEditText = (BootstrapEditText) footerView.findViewById(R.id.add_user_footer_lastname_edittext_id);

As you can see above, i can specify either "rootView" or "footerView" as the target of the findViewById.

Anyone able to help out with this issue? As it's driving me nuts at the moment..

Appall answered 23/7, 2014 at 22:8 Comment(0)
E
15

The simple solution is to put all your footer views in a view holder class and then perform the injections on different objects, while keeping the footer views easily accessible within the fragment.

@InjectView(R.id.users_listview_id) AutoUpdatingListView list;

private View footerView;
public class FooterViewHolder {
    @InjectView(R.id.add_user_footer_firstname_edittext_id) BootstrapEditText firstnameEditText;
    @InjectView(R.id.add_user_footer_middlename_edittext_id) BootstrapEditText middlenameEditText;
    @InjectView(R.id.add_user_footer_lastname_edittext_id) BootstrapEditText lastnameEditText;
    @InjectView(R.id.add_user_footer_cancel_button_id) BootstrapButton cancelButton;
    @InjectView(R.id.add_user_footer_okay_button_id) BootstrapButton okayButton;
    @InjectView(R.id.add_user_footer_facebook_button) BootstrapCircleThumbnail facebookButton;
    @InjectView(R.id.add_user_footer_google_plus_button) BootstrapCircleThumbnail googlePlusButton;
    @InjectView(R.id.add_user_footer_twitter_button) BootstrapCircleThumbnail twitterButton;
    @InjectView(R.id.add_user_footer_linkedin_button) BootstrapCircleThumbnail linkedInButton;

}
private FooterViewHolder footerViewHolder;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.user_fragment, container, false);
    footerView = inflater.inflate(R.layout.add_user_footer_view, container, false);
    footerViewHolder = new FooterViewHolder();

    ButterKnife.inject(this, rootView);
    ButterKnife.inject(footerViewHolder, footerView);

    list.setAdapter(adapter);

    return rootView;
}

BTW, it's considered bad practice to inflate views with a null parent.

Elstan answered 23/7, 2014 at 22:53 Comment(4)
Brilliant! Almost works just by copying your code, though it had 2 small errors. 1) ButterKnife doesn't allow @InjectView inside a private class, so had to make it public in order for it to compile 2) I have to pass 'null' as the root for the footerView, otherwise i get a 'java.lang.ClassCastException: android.widget.FrameLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams' exception Big thanks for the help, was much simpler than i had expected :)Appall
@Kasper that is a very bad practice, the foot will be in listview so it should get it as container possiblemobile.com/2013/05/layout-inflation-as-intendedFlew
IN this example how would you then set say a '@OnClick' method on one of the footerViewHolder's views? Or is that no longer possible? I did the above code but I could not annotate the view with '@OnClick' as it was not found.Auvil
@Auvil Any idea on implementing onclick method.Stonyhearted

© 2022 - 2024 — McMap. All rights reserved.