2016-07-29 12 views
6

Ponieważ obsługuje menu Data Binding w systemie Android? Piszę ten kod, ale błąd: "Błąd: (16, 26) Nie określono typu zasobu (w" widoczny "z wartością" @ {item.visible} ")."Jak powiązać Android DataBinding z Menu?

<menu xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:app="http://schemas.android.com/apk/res-auto"> 
<data> 
    <variable 
     name="item" 
     type="ru.dixy.ubiworkerchecklistsmobile.Models.Fact"/> 
    <import type="android.view.View"/> 
</data> 
    <item 
     android:id="@+id/compliteitem" 
     android:title="mybutton" 
     android:icon="@drawable/complite" 
     android:visible="@{item.visible}" 
     app:showAsAction="ifRoom" 
     /> 
</menu> 
+0

Czy należy dodać 'kod Fact'? –

Odpowiedz

3

AFAIK, w chwili obecnej powiązanie danych dotyczy tylko zasobów układu, a nie zasobów menu.

13

„W tej chwili, wiązania danych jest tylko do zasobów, a nie układ zasobów menu”

Ale zachowanie można osiągnąć Observable.OnPropertyChangedCallback. Najpierw trzeba określić OnPropertyChangedCallback:

private final Observable.OnPropertyChangedCallback propertyChangedCallback = new Observable.OnPropertyChangedCallback() { 
    @Override 
    public void onPropertyChanged(Observable observable, int i) { 
     getActivity().invalidateOptionsMenu(); 
    } 
}; 

Zakładając, że masz wiążące dla Faktu model w swoim fragmencie:

<variable 
    name="item" 
    type="ru.dixy.ubiworkerchecklistsmobile.Models.Fact"/> 

Teraz trzeba zarejestrować propertyChangedCallback i wyrejestrować go, gdy skończysz to:

@Override 
public void onStart() { 
    super.onStart(); 
    binding.getItem().addOnPropertyChangedCallback(propertyChangedCallback); 
} 

@Override 
public void onStop() { 
    super.onStop(); 
    binding.getItem().removeOnPropertyChangedCallback(propertyChangedCallback); 
} 

teraz jesteśmy gotowi aktualizacja wyświetlanie stanu w oparciu o Faktu model:

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    super.onCreateOptionsMenu(menu, inflater); 
    inflater.inflate(R.menu.menu_fact, menu); 
} 

@Override 
public void onPrepareOptionsMenu(Menu menu) { 
    super.onPrepareOptionsMenu(menu); 
    menu.findItem(R.id.compliteitem).setVisible(binding.getItem().isVisible()); 
} 
+1

również zwrócić uwagę, że 'int i' w wywołaniu zwrotnym jest identyfikatorem właściwości, który można sprawdzić za pomocą' propertyId == BR.propertyName' w celu uniknięcia częstego unieważniania menu – Philipp

2

Zdaję sobie sprawę, że jest to stare pytanie, ale chciałem dostarczyć rozwiązanie może więc pomóc innym z tym samym problemem. Można to osiągnąć za pomocą widoku akcji dla pozycji menu. Wymaga to sporo kodu, ale jest to podejście, które wykorzystuje MVVM i może być użyte do dowolnego powiązania danych.

To jest przykład, gdzie ikona pokazuje licznik i zmienia tło jeśli liczba jest większa niż 0.

Definiowanie elementu menu

MENU/main.xml

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item 
     android:id="@+id/action_count" 
     android:enabled="true" 
     android:icon="@drawable/ic_menu_red_square" 
     android:title="@string/count"/> 
</menu> 

Umożliwia zdefiniowanie modelu widoku dla pozycji menu.

public class CountMenuViewModel extends BaseObservable { 
    @Bindable 
    int count; 

    public CountMenuViewModel() {} 

    public int getCount() { 
     return count; 
    } 

    public void setCount(int count) { 
     this.count = count; 
     if (this.count < 0) { 
      this.count = 0; 
     } 
     notifyPropertyChanged(BR.count); 
    } 

    @Bindable({"count"}) 
    public @DrawableRes int getBackground() { 
     if (count > 0) { 
      return R.drawable.ic_menu_blue_square; 
     } 
     return R.drawable.ic_menu_red_square; 
    } 

    @Bindable({"count"}) 
    public String getCountText() { 
     if (count > 0) { 
      return String.valueOf(count); 
     } 
     return null; 
    } 
} 

Zdefiniuj wywołanie zwrotne, które zostanie zaimplementowane przez działanie po kliknięciu elementu menu.

public interface CountMenuActionCallback { 
    void onCountMenuItemClicked(); 
} 

Utwórz układ widoku akcji. Układ korzysta z klasy modelu widoku i ustawia tekst dla liczby i tła. Interfejs oddzwaniania jest używany dla OnClickListener dla widoku akcji.

układ/menu_action_count.xml

<?xml version="1.0" encoding="utf-8"?> 
<layout xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:tools="http://schemas.android.com/tools"> 

    <data> 
     <variable 
      name="data" 
      type="com.botnerd.samplesapp.CountMenuViewModel" 
      /> 
     <variable 
      name="callback" 
      type="com.botnerd.samplesapp.CountMenuActionCallback" 
      /> 
    </data> 
    <FrameLayout 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:onClick="@{() -> callback.onCountMenuItemClicked()}" 
     android:background="?android:attr/actionBarItemBackground"> 

     <ImageView 
      android:layout_width="32dp" 
      android:layout_height="32dp" 
      android:layout_margin="4dp" 
      android:src="@{data.background}" 
      tools:src="@drawable/ic_menu_red_square" 
      /> 

     <TextView 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_gravity="center" 
      android:text="@{data.countText}" 
      tools:text="30" 
      android:textSize="14dp" 
      android:maxLines="1" 
      android:textColor="@android:color/white" 
      tools:ignore="SpUsage"/> 
    </FrameLayout> 
</layout> 

Zauważ, że zwyczaj wiązania adapter służy do atrybutu android:src. Jest to dobry adapter do ustawienia ImageView src poprzez powiązanie danych.

@BindingAdapter({"android:src"}) 
public static void setSrc(ImageView view, @DrawableRes int resId) { 
    try { 
     view.setImageDrawable(ContextCompat.getDrawable(view.getContext(), resId)); 
    } catch (Resources.NotFoundException e) { 
    } 
} 

Na koniec nadmuchać menu i powiązać układ widoku akcji w działaniu.

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    getMenuInflater().inflate(R.menu.main, menu); 

    MenuItem menuItemCount = menu.findItem(R.id.action_count); 
    MenuActionCountBinding binding = MenuActionCountBinding.inflate(getLayoutInflater()); 
    binding.setData(mCountMenuViewModel); 
    binding.setCallback(mCountMenuActionCallback); 

    MenuItemCompat.setActionView(menuItemCount, binding.getRoot()); 
    MenuItemCompat.setShowAsAction(menuItemCount, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); 

    return super.onCreateOptionsMenu(menu); 
} 

Dla kompletności, tutaj są wszystkie pliki w próbce, które nie są zdefiniowane powyżej.

odkształcalne/ic_menu_blue_square.xml

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android"> 
    <padding android:bottom="4dp" 
      android:left="4dp" 
      android:right="4dp" 
      android:top="4dp"/> 
    <solid android:color="#000080"/> 
    <corners android:radius="2dp"/> 

</shape> 

odkształcalne/ic_menu_red_square.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"> 
    <padding android:bottom="4dp" 
      android:left="4dp" 
      android:right="4dp" 
      android:top="4dp"/> 
    <solid android:color="#800000"/> 
    <corners android:radius="2dp"/> 

</shape> 

układ/activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<layout 
    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"> 

    <data> 
     <variable 
      name="callback" 
      type="com.botnerd.samplesapp.MainActivityActionCallback" 
      /> 
    </data> 

    <android.support.constraint.ConstraintLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     tools:context="com.botnerd.samplesapp.MainActivity"> 

     <Button 
      android:id="@+id/button" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="-" 
      android:onClick="@{() -> callback.onMinusClicked()}" 
      android:layout_marginStart="79dp" 
      app:layout_constraintBaseline_toBaselineOf="@+id/button2" 
      tools:layout_constraintBaseline_creator="1" 
      tools:layout_constraintLeft_creator="1" 
      app:layout_constraintLeft_toLeftOf="parent"/> 

     <Button 
      android:id="@+id/button2" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="+" 
      android:onClick="@{() -> callback.onPlusClicked()}" 
      tools:layout_constraintTop_creator="1" 
      android:layout_marginStart="25dp" 
      android:layout_marginTop="97dp" 
      tools:layout_constraintLeft_creator="1" 
      app:layout_constraintTop_toTopOf="parent" 
      app:layout_constraintLeft_toRightOf="@+id/button"/> 
    </android.support.constraint.ConstraintLayout> 
</layout> 

MainActivityActionCallback.java

public interface MainActivityActionCallback { 
    void onPlusClicked(); 
    void onMinusClicked(); 
} 

MainActivity.java

public class MainActivity extends AppCompatActivity { 

    ActivityMainBinding mBinding; 
    CountMenuViewModel mCountMenuViewModel; 

    CountMenuActionCallback mCountMenuActionCallback = new CountMenuActionCallback() { 
     @Override 
     public void onCountMenuItemClicked() { 
      Toast.makeText(MainActivity.this, "Count clicked!", Toast.LENGTH_SHORT) 
        .show(); 
     } 
    }; 

    MainActivityActionCallback mActionCallback = new MainActivityActionCallback() { 
     @Override 
     public void onPlusClicked() { 
      mCountMenuViewModel.setCount(mCountMenuViewModel.getCount() + 1); 
     } 

     @Override 
     public void onMinusClicked() { 
      mCountMenuViewModel.setCount(mCountMenuViewModel.getCount() - 1); 
     } 
    }; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mCountMenuViewModel = new CountMenuViewModel(); 

     mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); 
     mBinding.setCallback(mActionCallback); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     getMenuInflater().inflate(R.menu.main, menu); 

     MenuItem menuItemCount = menu.findItem(R.id.action_count); 
     MenuActionCountBinding binding = MenuActionCountBinding.inflate(getLayoutInflater()); 
     binding.setData(mCountMenuViewModel); 
     binding.setCallback(mCountMenuActionCallback); 

     MenuItemCompat.setActionView(menuItemCount, binding.getRoot()); 
     MenuItemCompat.setShowAsAction(menuItemCount, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); 

     return super.onCreateOptionsMenu(menu); 
    } 


}