数据绑定Android Recycler视图

时间:2017-06-08 03:59:20

标签: android android-databinding

我正在使用android数据绑定,以下是我用来设置Variable

的类
public class DayTemp extends BaseObservable implements Serializable {

    @SerializedName("dt")
    long date;
    @SerializedName("pressure")
    double pressure;
    @SerializedName("humidity")
    long humidity;
    @SerializedName("temp")
    Temp temp;
    @SerializedName("weather")
    ArrayList<Weather> weathers;
    @SerializedName("speed")
    double speed;
    @SerializedName("deg")
    double deg;
    @SerializedName("clouds")
    double clouds;

    @Bindable
    public long getDate() {
        return date;
    }

    public void setDate(long date) {
        this.date = date;
        notifyPropertyChanged(BR.date);
    }

    @Bindable
    public double getPressure() {
        return pressure;
    }

    public void setPressure(double pressure) {
        this.pressure = pressure;
        notifyPropertyChanged(BR.pressure);
    }

    @Bindable
    public long getHumidity() {
        return humidity;
    }

    public void setHumidity(long humidity) {
        this.humidity = humidity;
        notifyPropertyChanged(BR.humidity);
    }

    @Bindable
    public Temp getTemp() {
        return temp;
    }

    public void setTemp(Temp temp) {
        this.temp = temp;
        notifyPropertyChanged(BR.temp);
    }

    @Bindable
    public ArrayList<Weather> getWeathers() {
        return weathers;
    }

    public void setWeathers(ArrayList<Weather> weathers) {
        this.weathers = weathers;
        notifyPropertyChanged(BR.weathers);
    }

    @Bindable
    public double getSpeed() {
        return speed;
    }

    public void setSpeed(double speed) {
        this.speed = speed;
        notifyPropertyChanged(BR.speed);
    }

    @Bindable
    public double getDeg() {
        return deg;
    }

    public void setDeg(double deg) {
        this.deg = deg;
        notifyPropertyChanged(BR.deg);
    }

    @Bindable
    public double getClouds() {
        return clouds;
    }

    public void setClouds(double clouds) {
        this.clouds = clouds;
        notifyPropertyChanged(BR.clouds);
    }
}

在这个POJO课程中,我可以将所有值设置为我的recyclerview bt,我无法访问天气学家的arraylist,也无法获得与之相关的字段。

public class Weather extends BaseObservable implements Serializable {

    @SerializedName("id")
    long id;
    @SerializedName("main")
    String main;
    @SerializedName("description")
    String desc;
    @SerializedName("icon")
    String icon;

    @Bindable
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
        notifyPropertyChanged(BR.id);
    }

    @Bindable
    public String getMain() {
        return main;
    }

    public void setMain(String main) {
        this.main = main;
        notifyPropertyChanged(BR.main);
    }

    @Bindable
    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
        notifyPropertyChanged(BR.desc);
    }

    @Bindable
    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
        notifyPropertyChanged(BR.icon);
    }
}

布局文件:

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

    <data>

        <import  type="com.weatherappforleftshift.currentlocation.DateUtils"/>

        <variable
            name="daytemp" type="com.weatherappforleftshift.currentlocation.model.DayTemp"/>


    </data>

           <TextView
                    android:id="@+id/weather_status"
                    android:layout_width="wrap_content"
                    android:layout_marginLeft="10dp"
                    android:layout_marginStart="10dp"
                    android:text="@{HOW TO SET TEXT HERE FROM weathers list}"
                    android:layout_height="wrap_content" />


</layout>

我想将天气等级的Icon和Description设置为我的Recyclerview。

如何在项目布局中实现这一点????

4 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

添加您的虚拟机:

@Bindable
public String getWeathersText() {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < weathers.size(); i++) {
        builder.append(weathers.get(i).getText);
    }
    return builder.toString();
}

并在你的布局xml:

<TextView
      android:id="@+id/weather_status"
      android:layout_width="wrap_content"
      android:layout_marginLeft="10dp"
      android:layout_marginStart="10dp"
      app:weathersText="@{daytemp.weathersText}"
      android:layout_height="wrap_content" />

我没有检查过,但我认为它应该有帮助...

答案 2 :(得分:0)

首先,您需要创建&#34;天气&#34;的变量/实例。布局xml中的类。

<variable
        name="weatherData" type="<packageName>.Weather"/>

你可以使用这个&#34; weatherData&#34;对象检索任何&#34;天气&#34;类属性

您只需要将来自RecyclerViewAdapter类的天气对象传递给xml。

bindind.setWeatherData(whetherList.get(position));

答案 3 :(得分:0)

有很多方法可以给这只猫蒙皮。但是您专门讲的是Binding,所以让我们以正确的方式进行:)。

您将需要一些东西,但请不要担心,其中大部分是一次性的样板,您可以在每个recyclerview中反复使用。那就是它的美。

1)布局中的RecyclerView

2)RecyclerView的通用绑定适配器

3)JMVStatic适配器,用于转换类型和设置

4)用于与RecyclerView的适配器通信的接口

差不多了,所以让我们进入代码。 顺便说一句,如果您不了解它,可以进行几乎所有的复制和粘贴,尽管它可能会做更多您需要的事情。另外,还有其他方法可以处理点击事件。您可以自己将它们嵌套到行布局文件中。

步骤1: 接口类

    interface IBindingRecyclerView<T> {

    /////////////////////////////////////////////////////////////////
    // EXTERNAL METHODS
    /////////////////////////////////////////////////////////////////
    fun getRowLayoutResourceId(): Int
    fun getBindingModelId(): Int
    fun getActionButtonResourceId(): Int
    fun onItemClick(model: T, position: Int)
    fun onItemLongClick(model: T, position: Int)
    fun onActionItemClick(model: T, position: Int, holder: BindingRecyclerViewAdapter.BindingHolder)

}

请注意*,您可能会或可能不会在乎点击处理程序,长按或操作项。一个动作项将是一个子按钮,不被认为是单击行。

步骤2: JVM静态绑定适配器

   object BindingAdapterMethods {

    /////////////////////////////////////////////////////////////////
    // MEMBERS
    /////////////////////////////////////////////////////////////////
    private var TAG: String = SSGlobals.SEARCH_STRING + "BindingAdapterMethods"



    /////////////////////////////////////////////////////////////////
    // METHODS
    /////////////////////////////////////////////////////////////////
    /**
     * This makes sure that the interface and observable list is set in the recyclerView's adapter. If the adapter is null,
     * then a new one is created.
     * @param view
     * @param iBindingRecyclerView
     * @param list
     */
    @JvmStatic
    @BindingAdapter(value = ["bindRcvInterface", "bindRcvList", "bindRcvPlusInterface"], requireAll = false)
    fun setBindingRecyclerViewProperties(view: RecyclerView, iBindingRecyclerView: IBindingRecyclerView<*>, list: ObservableArrayList<*>?, iBindingRecyclerViewPlus: IBindingRecyclerViewPlus<*>? = null) {
        if (view.adapter == null) {
            val layoutManager = LinearLayoutManager(view.context)
            view.layoutManager = layoutManager
            view.invalidateItemDecorations()
            view.addItemDecoration(VerticalItemDecoration(0))
            view.adapter = BindingRecyclerViewAdapter<Any?>()
        }

        val adapter = view.adapter as BindingRecyclerViewAdapter<*>
        adapter.setIBindingRecyclerView(iBindingRecyclerView, iBindingRecyclerViewPlus)
        if(list != null) {
            adapter.setList(list)
        }
    }
}

注意*这是简化的,仅添加一个适配器,随着绑定使用的增加,您将有很多。您可以忽略recyclerViewPlus参数,只需删除它即可。我将其用于布局的高度自定义,并将更多数据设置到行ui的子ui中,因为您知道数据绑定需要您遍历树。但是我离题了。

步骤3: 实施活动或分段

class MyListFragment : BaseFragment(), IBindingRecyclerView<YourListModelType> {
   /////////////////////////////////////////////////////////////////
   // MEMBERS
   /////////////////////////////////////////////////////////////////
   private lateinit var mBinding: FragmentYourItemListBinding
   private var mYourItemModelList : ObservableArrayList<YourListModelType> = ObservableArrayList()


   /////////////////////////////////////////////////////////////////
   // LIFE CYCLE OVERRIDES
   /////////////////////////////////////////////////////////////////
   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_your_item_list, container, false)
       mBinding.fragment = this
       mBinding.iBindingRecyclerView = this
       return mBinding.root
   }
   override fun onResume() {
       super.onResume()
       fillYourListOfItems()
   }

    /////////////////////////////////////////////////////////////////
    // PROPERTIES
    /////////////////////////////////////////////////////////////////
    fun getYourListItemModelList() : ObservableArrayList<YourListItemModelType> {
        return mYourItemModelList
    }


    /////////////////////////////////////////////////////////////////
    // IBINDINGRECYCLERVIEW OVERRIDES
    /////////////////////////////////////////////////////////////////
    override fun getRowLayoutResourceId(): Int {
        return R.layout.row_your_layout_file
    }
    override fun getBindingModelId(): Int {
        return BR.YourListModelType //defined in the xml coming up next
    }
    override fun getActionButtonResourceId(): Int {
        return -1 //if you aren't using, just return -1 or remove from interface
    }
    override fun onItemClick(model: YourListModelType, position: Int) {
        //handle the click of your item, launch a detail activity, whatever you need
    }
    override fun onItemLongClick(model: YourListModelType, position: Int) {
        //same as above, but if not using, you can remove from interface
    }
    override fun onActionItemClick(model: YourListModelType, position: Int, holder: BindingRecyclerViewAdapter.BindingHolder) {
        //if not using, you can remove from interface
    }


}

好,所有的设置都就位了,现在是简单的部分。 xml绑定。 :) 首先在顶部声明变量。

第4步可变声明

    <data>
        <variable name="fragment" type="com.yourpath.fragments.MyListFragment" />
        <variable name="iBindingRecyclerView" type="com.yourpath.interfaces.IBindingRecyclerView"/>
    </data>

对于所有回收者视图,始终无处不在地继续使用通用。

适用于大多数情况的第5步通用适配器(复制粘贴保持原样)

您可以删除不使用的接口回调。

class BindingRecyclerViewAdapter<T> : RecyclerView.Adapter<BindingRecyclerViewAdapter.BindingHolder>(), View.OnClickListener, View.OnLongClickListener {

    /////////////////////////////////////////////////////////////////
    // MEMBERS
    /////////////////////////////////////////////////////////////////
    private val MODEL_TAG = -124
    private val MODEL_POSITION_TAG = -125
    private var mRowLayoutResourceId: Int = 0
    private var mBindingModelId: Int = 0
    private var mActionButtonId: Int = 0
    private var mHasActionButton: Boolean = false
    private var mList: ObservableArrayList<*>? = null
    private lateinit var mIBindingRecyclerView: IBindingRecyclerView<T>
    private var mIBindingRecyclerViewPlus: IBindingRecyclerViewPlus<T>? = null


    /////////////////////////////////////////////////////////////////
    // PROPERTIES
    /////////////////////////////////////////////////////////////////
    /**
     * This is now how the interface needs to be set. This is taken care of in the @BindingAdapter
     * method "bind:rcvInterface" (BindingAdapterMethods). I also decided to take care of setting the
     * rowLayoutResourceId here, more as a "might as well" sort of thing, but also preventing the chance
     * of a null ref exception if we were to use mIBindingRecyclerView.getRowLayoutResourceId() and
     * mIBindingRecyclerView was null. Same goes for bindingModelId.
     * @param iBindingRecyclerView
     */
    fun setIBindingRecyclerView(iBindingRecyclerView: IBindingRecyclerView<*>, iBindingRecyclerViewPlus: IBindingRecyclerViewPlus<*>? = null) {
        mIBindingRecyclerView = iBindingRecyclerView as IBindingRecyclerView<T>
        mRowLayoutResourceId = iBindingRecyclerView.getRowLayoutResourceId()
        mBindingModelId = iBindingRecyclerView.getBindingModelId()
        mActionButtonId = iBindingRecyclerView.getActionButtonResourceId()
        mHasActionButton = mActionButtonId > 0
        mIBindingRecyclerViewPlus = iBindingRecyclerViewPlus as IBindingRecyclerViewPlus<T>?
    }
    /**
     * This is how the list is set and any changes made will be notified here. If notifyDataSetChanged()
     * is not called here, then the view will not be updated with the list changes. Setting the list gets
     * taken care of in the @BindingAdapter method "bind:rcvList" (BindingAdapterMethods). Anytime the list
     * changes in the activity/fragment, it will trigger the "bind:rcvList" method, and that will call
     * setList(), thus updating the list and notifying data set changed which updates the view properly.
     * @param list
     */
    fun setList(list: ObservableArrayList<*>) {
        mList = list
        notifyDataSetChanged()
    }


    /////////////////////////////////////////////////////////////////
    // BASE CLASS OVERRIDES
    /////////////////////////////////////////////////////////////////
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder {
        val inflater = LayoutInflater.from(parent.context)
        val viewDataBinding = DataBindingUtil.inflate<ViewDataBinding>(inflater, mRowLayoutResourceId, parent, false)
        return BindingHolder(viewDataBinding)
    }
    override fun onBindViewHolder(holder: BindingHolder, position: Int) {
        val model = mList!![position]
        holder.binding.setVariable(mBindingModelId, model)
        holder.binding.root.setTag(MODEL_TAG, model)
        holder.binding.root.setTag(MODEL_POSITION_TAG, position)
        holder.binding.root.setOnClickListener(this)
        holder.binding.root.setOnLongClickListener(this)

        if(mIBindingRecyclerViewPlus != null){
            mIBindingRecyclerViewPlus?.onRowBinding(model as T, position, holder)
        }

        if (mHasActionButton) {
            val btnAction = holder.binding.root.findViewById<View>(mActionButtonId)
            btnAction.setTag(MODEL_TAG, model)
            btnAction.setTag(MODEL_POSITION_TAG, position)
            onActionClick(btnAction, holder)
        }

        holder.binding.executePendingBindings()
    }
    override fun getItemCount(): Int {
        return if (mList == null) 0 else mList!!.size
    }


    ////////////////////////////////////////////////////////////////
    // CLICK LISTENERS
    ////////////////////////////////////////////////////////////////
    override fun onClick(v: View) {
        val model = v.getTag(MODEL_TAG) as T
        val position = v.getTag(MODEL_POSITION_TAG) as Int
        mIBindingRecyclerView.onItemClick(model, position)
    }
    override fun onLongClick(v: View): Boolean {
        val model = v.getTag(MODEL_TAG) as T
        val position = v.getTag(MODEL_POSITION_TAG) as Int
        mIBindingRecyclerView.onItemLongClick(model, position)
        return true
    }
    fun onActionClick(btnAction: View, holder: BindingHolder) {
        btnAction.setOnClickListener {
            val model = btnAction.getTag(MODEL_TAG) as T
            val position = btnAction.getTag(MODEL_POSITION_TAG) as Int
            mIBindingRecyclerView.onActionItemClick(model, position, holder)
        }
    }


    ////////////////////////////////////////////////////////////////
    // SCOPED CLASSES
    ////////////////////////////////////////////////////////////////
    class BindingHolder(var binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root)

}

最后一步 使用它:)。

第6步绑定您的回收站视图

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:paddingStart="@dimen/dp_20"
        android:paddingEnd="@dimen/dp_20"
        app:bindRcvInterface="@{iBindingRecyclerView}"
        app:bindRcvList="@{fragment.getYourListItemModelList}"/>

注意*,您无需指定()符号,只需如上所示使用它即可。

所以,好消息是,这大部分是一次性设置。也可以在您的应用中使用它。

OH YEAH和Optional,它在我的代码中,但可能会做您自己的变体,以处理回收站视图的外观。

垂直装饰器

class VerticalItemDecoration (private var spacingInPx: Int) : RecyclerView.ItemDecoration() {

/*///////////////////////////////////////////////////////////////
// ITEM DECORATION OVERRIDES
*////////////////////////////////////////////////////////////////
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
    outRect.bottom = spacingInPx
}

}

可重复使用的物品包括:

  • 界面
  • jvm静态适配器
  • 回收站视图适配器
  • 垂直装饰器

所以实际上您只是在实现接口,以可观察列表的形式提供列表,在onCreate中设置变量,并将两行放在xml中并重复:)。

快乐编码。希望这会有所帮助。