Databinding returning null. Is it normal? - android

I'm using databinding, and looks like tab item is returned null from databinding (but not gameTypes), is that normal? Other views are working fine, so there is no problem with implementation of databinding. Here is part of layout file.
<android.support.design.widget.TabLayout
android:id="#+id/gameTypes"
android:layout_width="0dp"
android:layout_height="48dp"
android:background="#android:color/white"
>
<android.support.design.widget.TabItem
android:id="#+id/football"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:tag="football"
android:text="Football"
/>
<android.support.design.widget.TabItem
android:id="#+id/basketball"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:tag="basketball"
android:text="Basketball"/>
</android.support.design.widget.TabLayout>
Here is code that I'm trying to find selected tab;
private Boolean isSelectedTab(TabItem item, TabLayout.Tab tab) {
if (tab.getTag().equals(item.getTag()))
return true;
return false;
}
Error is; item is null which is databinding.basketball. I think shouldn't be null since it's TabItem.
Thanks.

Your code does not line up with your XML, so that's probably one problem. But you might be running into an issue we had with TabLayouts and databinding.
The root cause appears to be that TabLayout uses TabItem in XML, but it converts it into a Tab at runtime. This screws up the internal mapping databinding uses to create its references. In our case, our TabItem instance was being cast from the wrong object. In your case, sounds like it might just be a null object.
In either case, it does't appear that you can use TabLayout with databinding reliably. We ended up creating a custom View that just wraps a TabLayout and then "binds" data to it manually by accessing its Tab items directly.
For example, a layout with a TabLayout:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="viewModel" type="com.app.ViewModel" />
</data>
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#color/white"
app:onTabSelectedListener="#{viewModel.onTabSelectedListener}">
<android.support.design.widget.TabItem
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="#layout/custom_tab_layout">
</android.support.design.widget.TabItem>
<android.support.design.widget.TabItem
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="#layout/custom_tab_layout">
</android.support.design.widget.TabItem>
</android.support.design.widget.TabLayout>
And then a custom view that wraps that:
public class CustomTabLayout extends FrameLayout {
private CustomTabLayoutBinding mBinding;
public CustomTabLayout(#NonNull Context context) {
this(context, null);
}
public CustomTabLayout(#NonNull Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomTabLayout(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater inflater = LayoutInflater.from(context);
View tabLayout = inflater.inflate(R.layout.custom_tab_layout, this, false);
addView(tabLayout);
if (!isInEditMode()) {
mBinding = CustomTabLayoutBinding.bind(tabLayout);
}
}
public void setViewModel(#Nullable ViewModel viewModel) {
mBinding.setViewModel(viewModel);
if (viewModel != null) {
updateTabAtIndex(viewModel.getFirstTabViewModel(), 0, viewModel.getSelectedIndex());
updateTabAtIndex(viewModel.getSecondTabViewModel(), 1, viewModel.getSelectedIndex());
}
}
private void updateTabAtIndex(TabViewModel tabViewModel, int index, int selectedIndex) {
TabLayout.Tab tab = mBinding.tabLayout.getTabAt(index);
if (tab == null) {
return;
}
View customView = tab.getCustomView();
if (customView == null) {
return;
}
if (index == selectedIndex) {
tab.select();
}
TextView textView = (TextView) customView.findViewById(R.id.title);
textView.setText(tabViewModel.getTitleText());
TextView subTitleTV = (TextView) customView.findViewById(R.id.subtitle);
subTitleTV.setText(tabViewModel.getSubTitleText());
}
}
Then in the layout that you need a TabLayout, use your custom view instead:
<com.app.CustomTabLayout
android:id="#+id/custom_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/default_toolbar_elevation"
app:viewModel="#{viewModel.getTabsViewModel}" />
We're using MVVM here, but hopefully you get the gist: by providing a public setViewModel (or setMyData or whatever) method, you can still leverage databinding where you use the custom tab layout, but then control manually setting the attributes on the Tab objects in the TabLayout.
Hope that helps!

item is databinding.itemBasketball
Not according to your code snippet. Your code snippet shows that you are calling isSelectedTab(b.itemFootballTypes, tab). There is nothing named itemFootballTypes in your layout XML in your question. There is an itemFootball tab, though.

Related

How to change the custom preference layout's imageview programmatically?

I used settings activity to let a user select from different resources in my android app. All preference items are checkbox. I've defined a custom layout for each preference and connect it to the checkbox. When I click the preference item it is working properly but I can't understand at which position the preference is. So I want to change the imageview of the custom layout programmatically when I click on the preference item. Is there a way to do that?
Below, the second item is the default text, I want to change the layout to the first one. Everything is working but I want to change the plus image to another image programmatically when I click on this item (to understand that it is checked). Since this is settings activity, I couldn't find a way (there is no findviewbyid etc..) Android behaves the whole custom layout as a checkbox (you can click anywhere on the line)
Settings.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:layout="#layout/source_item"
android:key="gundem_haberturk"
android:title="#string/haberturk"
android:defaultValue="false"/>
</PreferenceScreen>
Custom Layout.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/layout_source_item"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/iv_source_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="100dp"
android:maxHeight="40dp"
android:src="#drawable/logo_haberturk"/>
<TextView
android:id="#+id/tv_source_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Habertürk"
android:textSize="22sp"
android:textStyle="bold" />
<ImageView
android:id="#+id/iv_source_selector"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="#drawable/checkbox_unchecked"/>
</RelativeLayout>
Settings Fragment:
public class GundemSettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle bundle, String rootKey) {
addPreferencesFromResource(R.xml.gundem_settings);
}
}
Settings Activity:
public class GundemSettingsActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gundem_settings);
Toolbar toolbar = findViewById(R.id.settings_toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
}
Settings Activity xml
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hhs.haberler.Settings.GundemSettingsActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/settings_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<fragment
android:layout_marginTop="?attr/actionBarSize"
android:id="#+id/settings_fragment"
android:name="com.example.haberler.Settings.GundemSettingsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.design.widget.CoordinatorLayout>
You can create a custom Preference which extends from CheckBoxPreference and use it just like the CheckBoxPreference:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<your.package.name.CustomCheckBoxPreference
android:layout="#layout/custom_checkbox_preference"
android:key="custom_checkbox_pref"
android:title="CustomCheckBoxPreferenceTitle"
android:defaultValue="false"/>
</PreferenceScreen>
Please note that according to the documentation for the android:layout atttribute one has to use specific resource id's for the layout's root ViewGroup as well as the TextViews for title and summary. This will ensure that the customized Preference behaves just like any stock Preference.
By overriding onBindViewHolder(PreferenceViewHolder) you can "find" the ImageView and assign it to a corresponding field ivSourceSelector. And by overriding setChecked() you can swap the drawables when the checked state of the Preference changes.
Having said that, here's the code for CustomCheckBoxPreference:
public class CustomCheckBoxPreference extends CheckBoxPreference {
private ImageView ivSourceSelector;
public CustomCheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomCheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CustomCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomCheckBoxPreference(Context context) {
super(context);
}
#Override
public void setChecked(boolean checked) {
super.setChecked(checked);
if(ivSourceSelector != null) {
ivSourceSelector.setImageResource(getResourceId(checked));
}
}
#Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
ivSourceSelector = holder.itemView.findViewById(R.id.iv_source_selector);
if(ivSourceSelector != null){
ivSourceSelector.setImageResource(getResourceId(isChecked()));
}
}
private int getResourceId(boolean checked) {
return checked ? R.drawable.custom_checkbox_checked : R.drawable.custom_checkbox_unchecked;
}
}

Why is Android Studio designer displaying my custom view nested inside itself, while it isn't

I've got a custom view for my app named AvatarView:
<?xml version="1.0" encoding="utf-8"?>
<com.ulouder.views.AdvancedRelativeLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center_horizontal"
android:layout_margin="0dp"
android:padding="0dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CP"
android:id="#+id/initialsView"
android:layout_alignTop="#+id/avatarView"
android:layout_alignLeft="#+id/avatarView"
android:layout_alignBottom="#+id/avatarView"
android:layout_alignRight="#+id/avatarView"
android:background="#drawable/avatar_background"
android:textColor="#color/white"
android:gravity="center"
android:textStyle="bold"
android:textSize="8sp" />
<com.makeramen.roundedimageview.RoundedImageView
app:riv_corner_radius="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/avatarView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="4dp"
app:riv_border_color="#color/lightGray"
app:riv_border_width="0.2dp" />
</com.uLouder.views.AdvancedRelativeLayout>
AdvancedRelativeLayout is just a superclass of RelativeLayout with a small fix, nothing special there. Then, I've created a view that uses my custom view:
<?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">
<com.ulouder.views.AvatarView
android:layout_width="50dp"
android:layout_height="50dp"/>
</LinearLayout>
Nothing fancy either. But in the designer view of the second layout XML, I'm getting this:
The editor displays my view hierarchy like it has a nested instance of itself, while clearly there isn't. If I delete either one, they both get deleted. If I declare attributes on one of them, other also gets it. They are clearly the same instance. The only exception is setting an ID. Then the problem disappears, and only single instance is displayed as expected.
I've rebuilt the project, restarted Android Studio, but it's still the same. What am I doing wrong?
UPDATE: Nope, now, after editing id, the problem still continues again.
UPDATE 2: It's not just a layout so I can't use <include> tag. It's a custom view which has custom logic inside.
UPDATE 3: Here is my custom view's (relevant) code:
public class AvatarView extends FrameLayout {
public AvatarView(Context context) {
super(context);
init();
}
TextView initialsView;
RoundedImageView imageView;
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
void init(){
inflate(getContext(), R.layout.view_avatar, this);
initialsView = (TextView) findViewById(R.id.innerInitialsView);
imageView = (RoundedImageView) findViewById(R.id.innerImageView);
}
#SuppressWarnings("SuspiciousNameCombination")
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec); //always square
imageView.setCornerRadius(widthMeasureSpec / 2f);
initialsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, widthMeasureSpec * 30f);
}
}
UPDATE 4: It appears that this happens wherever I put my custom AvatarView class, not just at one place.
I did not find any reason to inflate the same view inside your class constructor method after checking the custom views documentation. Try to remove the inflate inside your init method.
...
public AvatarView(Context context) {
super(context);
init();
}
...
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
void init(){
// inflate(getContext(), R.layout.view_avatar, this);
initialsView = (TextView) findViewById(R.id.innerInitialsView);
imageView = (RoundedImageView) findViewById(R.id.innerImageView);
}
...

How do I programatically access a spinner located inside the header of the NavigationView from the design support library?

I am using the new design support library. For the navigation view you can specify a header. What I'm trying to do is programatically access a spinner, which is located inside the nav_header xml.
Spinner spinner = (Spinner) findViewById(R.id.spinner); // Normal initialization of a spinner
Located in activity_main.xml
<android.support.design.widget.NavigationView
android:id="#+id/navigation_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/nav_header" <-- declaring nav_header as header layout
app:itemIconTint="#color/primary_text"
app:itemTextColor="#color/primary_text"
app:menu="#menu/nav_draw_items" />
nav_header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/filter_toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="#2364AA"
android:elevation="4dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:navigationContentDescription="#string/abc_action_bar_up_description"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<LinearLayout
android:id="#+id/spinner_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/spinner_front"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:layout_gravity="center_vertical"
android:text="Sort By: "
android:textColor="#android:color/white"
android:textSize="16sp"/>
<Spinner
android:id="#+id/spinner" <-- what I'm trying to access
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:spinnerMode="dropdown" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
</LinearLayout>
Do something like this:-
//Your navigation view
NavigationView navigationView = (NavigationView) findViewById(R.id.navigation_left);
//Now get the Spinner from the navigationView
Spinner spinner = (Spinner) navigationView.findViewById(R.id.spinner);
I don't know if it helps you, but my solution to get all the views from the Header's navigation view was to create a custom view based on Google's Navigation View that intercepts the methods which set the header's view and binds the databinding based on its view, so the custom class is something like that:
/**
* Created by pokawa on 25/10/15.
*/
public class CustomNavigationView extends NavigationView {
private static final String EXCEPTION_TAG_NULL_HEADER = "CustomNavigationView";
private static final String EXCEPTION_MESSAGE_NULL_HEADER = "You have to set a header first";
private View header;
public CustomNavigationView(Context context) {
super(context);
}
public CustomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* Overridden to store the header's view
*
* #param res header view id
* #return header's view
*/
#Override
public View inflateHeaderView(int res) {
header = super.inflateHeaderView(res);
return header;
}
/**
* Overridden to store the header's view
*
* #param view header
*/
#Override
public void addHeaderView(View view) {
this.header = view;
super.addHeaderView(view);
}
/**
* Method used to retrieve header's data binding
*
* #return Header's view binding
*/
public ViewDataBinding getHeaderDataBinding() {
try{
return DataBindingUtil.bind(header);
} catch (NullPointerException exception) {
Log.i(EXCEPTION_TAG_NULL_HEADER, EXCEPTION_MESSAGE_NULL_HEADER);
throw exception;
}
}
}
And the XML to will be something like that:
<your.package.path.CustomNavigationView
android:id="#+id/navigation_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/nav_header" <-- declaring nav_header as header layout
app:itemIconTint="#color/primary_text"
app:itemTextColor="#color/primary_text"
app:menu="#menu/nav_draw_items" />
Finally, an example how to retrieve the databinding:
public class MainActivity extends BaseActivity {
(...)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
YourLayoutBinding binding = DataBindingUtil.setContentView(this, R.layout.your_layout);
NavHeaderBinding headerBinding = ((NavHeaderBinding) binding.navigationLeft.getHeaderDataBinding());
Spinner spinner = headerBinding.spinnerLl;
(...)
}
(...)
}
PS: Of course I'm assuming that you're using new Google's feature (DataBinding), let me know if you're using another approach to inject view (e.g. ButterKnife) and I could help you with this.
See ya.
In the current version of the design support library you can simply use the getHeaderView method, e.g.
View header = navigationView.getHeaderView(0);
TextView loginName = (TextView) header.findViewById(R.id.loginName);
loginName.setText(mApiHelper.getName());

Adding text hint to Android SwipeRefreshLayout

How do I add a hint on the top of a listView like "Pull down to refresh" which is contained in a swipeRefreshLayout from android.support.v4.
The pull down to refresh works but I want to add a text whenever the user pulls the listview slightly down.
EDIT 10/21/2014
If you update the support-v4 to the latest version (at least 21.0.0) you can use the built-in loading indicator!
I just came up with a simple, yet effective, solution.
The idea is to add a custom ViewGroup that grows its height when the SwipeRefreshLayout child gets pulled down. In this ViewGroup you will put everything you need for your hint (TextViews, ImageViews, ...).
I chose to extend a RelativeLayout because it makes easier to position your "hint" elements.
1) Create a custom widget as follows:
public class SwipeRefreshHintLayout extends RelativeLayout {
public SwipeRefreshHintLayout(Context context) {
super(context);
}
public SwipeRefreshHintLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwipeRefreshHintLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setSwipeLayoutTarget(final SwipeRefreshLayout swipeRefreshLayout) {
final View swipeTarget = swipeRefreshLayout.getChildAt(0);
if (swipeTarget == null) {
return;
}
swipeTarget.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
private Rect oldBounds = new Rect(), newBounds = new Rect();
#Override
public boolean onPreDraw() {
newBounds.set(swipeTarget.getLeft(), swipeRefreshLayout.getTop(), swipeTarget.getRight(), swipeTarget.getTop());
if (!oldBounds.equals(newBounds)){
getLayoutParams().height = newBounds.height();
requestLayout();
oldBounds.set(newBounds);
}
return true;
}
});
}
}
2) In your Fragment or Activity layout use this custom widget.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.widget.SwipeRefreshHintLayout
android:id="#+id/swipe_hint"
android:layout_width="match_parent"
android:layout_height="0dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="#string/label_swipe_to_refresh"/>
<!-- Any other view positioned using RelativeLayout rules -->
</com.example.widget.SwipeRefreshHintLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
3) Then, in your Activity onCreate() or in your Fragment onCreateView(), put those lines:
mSwipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_container);
mSwipeRefreshHintLayout = (SwipeRefreshHintLayout) rootView.findViewById(R.id.swipe_hint);
mSwipeRefreshHintLayout.setSwipeLayoutTarget(mSwipeRefreshLayout);
Done!

Alternatives to creating a Compound Control by extending a Layout

I want to create a custom Compound Control in Android that holds some logic. For the purpose of this example, let's say I want it to switch between two views when clicked.
According to the API guide, it looks like the way to do that is to create a new class that extends Layout, and do everything in there.
So I did just that:
I created a XML layout to inflate for my custom component:
.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/view1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Hello"/>
<TextView
android:id="#+id/view2"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="World"
android:visibility="gone"/>
</RelativeLayout>
Then I created my custom Layout class, and added the logic in there:
public class MyWidget extends RelativeLayout {
public final View mView1;
public final View mView2;
public MyWidget(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout view = (RelativeLayout) inflater.inflate(R.layout.my_widget, this, true);
mView1 = view.findViewById(R.id.view1);
mView2 = view.findViewById(R.id.view2);
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
switchViews();
}
});
}
public void switchViews() {
if (mView1.getVisibility() == View.VISIBLE) {
mView1.setVisibility(View.GONE);
} else {
mView1.setVisibility(View.VISIBLE);
}
if (mView2.getVisibility() == View.VISIBLE) {
mView2.setVisibility(View.GONE);
} else {
mView2.setVisibility(View.VISIBLE);
}
}
}
And finally, I included my custom view in some layout:
.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.MyWidget
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</RelativeLayout
And that works.
I am not completely happy with that solution though, for 2 reasons:
In the constructor of MyWidget, I instantiate 2 nested RelativeLayout by calling the super() constructor, and the one that is at the root of my XML layout. For that, I know I can instead use <merge> as my XML root and that gets me rid of the extra RelativeLayout. Except that defining XML attributes, such as android:background on my <merge> tag doesn't have any effect, so I have to define it programmatically, which is not as nice.
The custom View is a subclass of RelativeLayout, and therefore expose methods it inherits from it, such as addView(), even if it doesn't make sense to add child views to it. I know I can override those methods to prevent users from doing that, but I would still find it cleaner to inherit from View.

Categories

Resources