2016-07-29 15 views
6

Vì nó hỗ trợ menu Ràng buộc dữ liệu trong Android? Tôi viết mã này nhưng lỗi: "Lỗi: (16, 26) Không có loại tài nguyên nào được chỉ định (tại 'hiển thị' có giá trị '@ {item.visible}')."Cách ràng buộc Android DataBinding với 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

bạn có thể vui lòng thêm 'Fact' mã? –

Trả lời

3

AFAIK, hiện tại, ràng buộc dữ liệu chỉ dành cho tài nguyên bố cục chứ không phải tài nguyên menu.

13

"Tại thời điểm này, dữ liệu ràng buộc duy nhất là tài nguyên bố cục, không nguồn menu"

Nhưng, hành vi có thể đạt được với Observable.OnPropertyChangedCallback. Trước tiên, bạn cần phải xác định OnPropertyChangedCallback:

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

Giả sử rằng bạn có một ràng buộc cho Fact mô hình trong đoạn của bạn:

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

Bây giờ bạn cần phải đăng ký propertyChangedCallback và unregister nó khi bạn đang thực hiện với nó:

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

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

Bây giờ chúng tôi sẵn sàng cập nhật trạng thái xem của bạn dựa trên Sự kiện mô hình:

@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

cũng lưu ý rằng 'int i' trong hàm gọi lại là id thuộc tính có thể được kiểm tra bằng' propertyId == BR.propertyName' để tránh bị vô hiệu hóa menu thường xuyên – Philipp

2

Tôi nhận ra đây là một câu hỏi cũ, nhưng tôi muốn cung cấp một giải pháp để nó có thể giúp đỡ người khác với cùng một vấn đề. Điều này có thể đạt được bằng cách sử dụng chế độ xem hành động cho mục menu. Nó đòi hỏi một chút mã công bằng, nhưng đó là một cách tiếp cận sử dụng MVVM và có thể được sử dụng cho bất kỳ ràng buộc dữ liệu nào.

Đây là một ví dụ trong đó biểu tượng cho thấy một số thay đổi và nền nếu số lượng lớn hơn 0.

Xác định mục trình đơn

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> 

Xác định mô hình xem cho mục 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; 
    } 
} 

Xác định cuộc gọi lại sẽ được thực hiện bởi hoạt động khi mục menu được nhấp.

public interface CountMenuActionCallback { 
    void onCountMenuItemClicked(); 
} 

Tạo bố cục cho chế độ xem tác vụ. Bố cục sử dụng lớp mô hình chế độ xem và đặt văn bản cho số lượng và nền. Giao diện gọi lại được sử dụng cho OnClickListener cho chế độ xem hành động.

bố trí/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> 

Lưu ý rằng một adapter tùy chỉnh ràng buộc được sử dụng cho thuộc tính android:src. Đây là một bộ điều hợp tốt để thiết lập ImageView src thông qua ràng buộc dữ liệu.

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

Cuối cùng, tăng cấp độ và ràng buộc bố cục chế độ xem hành động trong hoạt động.

@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); 
} 

Để hoàn tất, dưới đây là tất cả các tệp trong mẫu không được xác định ở trên.

drawable/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> 

drawable/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> 

bố trí/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); 
    } 


} 
Các vấn đề liên quan