MvvmCross:MvxAdapter GetBindableView 方法在第一个无限循环 child

MvvmCross: MvxAdapter GetBindableView method loops indefinitely on first child

我的适配器的 GetBindableView 方法通常为我的 MvxGridView 的所有 child 调用,但是它在第一个 child.

上无限循环

在 MvxFragment 中,我在 OnCreateView 方法中将适配器设置为 MvxGridView:

public class MetronomeFragment : MvxFragment<MetronomeViewModel>, View.IOnTouchListener
{
    public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        var ignored = base.OnCreateView (inflater, container, savedInstanceState);
        var view = this.BindingInflate (Resource.Layout.fragment_metronome, null);

        // GridView
        var gridView = view.FindViewById<MvxGridView>(Resource.Id.grid_view);
        gridView.Adapter = new CustomAdapter (Activity, (MvxAndroidBindingContext)BindingContext);

        return view;
    }
}

我的部分观点:

<Mvx.MvxGridView
    android:id="@+id/grid_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:stretchMode="columnWidth"
    android:numColumns="5"
    android:verticalSpacing="@dimen/metronome_grid_view_vertical_spacing"
    local:MvxBind="ItemsSource MeasureViewModel.Measure.BeatList"
    local:MvxItemTemplate="@layout/template_item_metronome_beat" />

我的模板:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="@dimen/item_metronome_beat_layout_width"
    android:layout_height="@dimen/item_metronome_beat_layout_height"
    android:layout_gravity="center"
    local:cardBackgroundColor="@color/card_view"
    local:cardCornerRadius="@dimen/card_view_corner_radius"
    local:MvxBind="CardElevation BoolToElevation(IsPlaying, 2); Alpha BoolToAlpha(IsPlaying, 0.5)">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="@dimen/item_metronome_beat_margin">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            local:MvxBind="DrawableId BeatToImageResource(.)" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:textSize="@dimen/text_small"
            local:MvxBind="Text Number" />
    </RelativeLayout>
</android.support.v7.widget.CardView>

这是我的自定义适配器:

public class CustomAdapter : MvxAdapter
{
    public CustomAdapter(Context context, IMvxAndroidBindingContext bindingContext)
            : base(context, bindingContext)
    {
    }

    protected override View GetBindableView(View convertView, object source, int templateId)
    {
        var beat = (Beat)source;
        Mvx.Trace (beat.Number.ToString ());

        return base.GetBindableView(convertView, source, templateId);
    }
}

为了这个测试目的,我只记录节拍数 (DataContext object)。该列表包含 4 个节拍,输出为:1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... 它总是在第一个循环 child!!!

我正在使用 MvvmCross 4.0.0-beta5。

有人有想法吗?

干杯

终于找到解释了! 由于 ViewTreeObserver.GlobalLayout 事件和 RelativeLayout.

的组合,这是意外的屏幕刷新

我的主要 activity OnCreate 方法中有这段代码可以显示(作为临时屏幕调试信息)屏幕尺寸和密度:

var contentView = FindViewById<View> (Window.IdAndroidContent);
var sizeText = FindViewById<Android.Widget.TextView> (Resource.Id.size_text);
contentView.ViewTreeObserver.GlobalLayout += (sender, e) => {
    var height = (int) ((contentView.Height)/Resources.DisplayMetrics.Density);
    var width = (int) ((contentView.Width)/Resources.DisplayMetrics.Density);
    sizeText.Text = height + " x " + width + " " + Resources.DisplayMetrics.DensityDpi.ToString();
};

我不知道的是,这个方法被重复调用了。这意味着 TextView 中的文本每秒更改几次(即使大小没有更改)。

我的主要观点是:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background">
    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/size_text" />
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/toolbar"
        android:layout_above="@+id/ad_view" />
    <com.google.android.gms.ads.AdView
        android:id="@id/ad_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        local:adSize="BANNER"
        local:adUnitId="@string/ad_unit_id" />
</RelativeLayout>

我的 FrameLayout 包含我的 GridView 包含在 RelativeLayout 以及我的 TextView 中。由于 TextView 的内容总是变化的,因此重新计算每个视图的大小。 GridView 也是这种情况,这意味着调用 GetBindable 方法。

要避免在获取大小时出现此调用循环,请让您的 activity 实现 Android.Views.ViewTreeObserver.IOnGlobalLayoutListener 并将其添加到 OnCreate 方法中:

var contentView = FindViewById<View> (Window.IdAndroidContent);
contentView.ViewTreeObserver.AddOnGlobalLayoutListener(this);

并添加此方法:

public void OnGlobalLayout ()
{
    var metrics = Resources.DisplayMetrics;
    var contentView = FindViewById<View> (Window.IdAndroidContent);
    var sizeText = FindViewById<Android.Widget.TextView> (Resource.Id.size_text);
    var height = (int) ((contentView.Height)/metrics.Density);
    var width = (int) ((contentView.Width)/metrics.Density);
    sizeText.Text = height + " x " + width + " " + metrics.DensityDpi.ToString();
    contentView.ViewTreeObserver.RemoveOnGlobalLayoutListener(this);
}

大家周末愉快!!!