محولات الربط

الإعلانات

محولات الربط

تكون محولات الربط مسؤولة عن إجراء إستدعاءات إطار العمل المناسبة لتحديد القيم. أحد الأمثلة على ذلك هو..

تعيين قيمة خاصية مثل إستدعاء دالة ضبط النص ()setText. مثال آخر و هو تعيين مستمع حدث مثل إستدعاء الداله ()setOnClickListener.

تسمح لك مكتبة ربط البيانات بتعيين الدالة المستدعاه لتعيين قيمة، وتوفير منطق الربط الخاص بك، وتحديد نوع الكائن الذي تم إرجاعه بإستخدام المحولات.

 

ضبط قيم السمات


عندما تتغير قيمة ربط، يجب أن تقوم فئة الربط المُنشئه، بإستدعاء دالة التعيين في طريقة العرض التي تحتوي على تعبير الربط.

يمكنك السماح لمكتبة ربط البيانات، بتحديد الداله تلقائياً، أو إعلان الداله بشكلٍ صريح، أو توفير منطق مخصص لتحديد داله.

 

إختيار داله تلقائياً

بالنسبة إلى السمة المسماه نموذج example، تحاول المكتبة العثور تلقائياً على الدالة (setExample (arg التي تقبل أنواع متوافقة كوسيط.

لا يتم الأخذ في الإعتبار نطاق السمة، يتم إستخدام اسم السمة، ونوعها فقط عند البحث عن دالة ما.

على سبيل المثال، بالنظر إلى التعبير "{android:text="@{user.name ، تبحث المكتبة عن دالة (setText (arg التي تقبل النوع..

الذي يتم إرجاعه بواسطة ()user.getName . إذا كان نوع الإرجاع الخاص بـ ()user.getName عبارة عن سلسله String، سوف تبحث المكتبة عن..

دالة ()setText التي تقبل وسيط سلسلة String. إذا قام التعبير بدلاً من ذلك، بإرجاع عدد صحيح int، سوف تبحث المكتبة عن دالة ()setText..

التي تقبل وسيط العدد الصحيح. يجب أن يقوم التعبير بإرجاع النوع الصحيح، يمكنك إلقاء قيمة الإرجاع إذا لزم الأمر.

ربط البيانات يعمل، حتى في حالة عدم وجود أي سمة بالأسم المحدد. يمكنك بعد ذلك إنشاء سمات لأي دالة ضبط بإستخدام ربط البيانات.

على سبيل المثال، لا تحتوي فئة الدعم DrawerLayout على أي سمات، ولكنها تحتوي الكثير من دوال الضبط.

يستخدم المخطط التالي دوال (setScrimColor (int و (setDrawerListener (DrawerListener تلقائياً كدوال..

ضبط لسمات app:scrimColor و app:drawerListener، على التوالي:

 

 

تحديد اسم داله مخصص

تحتوي بعض السمات على دوال ضبط لا تتطابق بالأسم. في هذه الحالات، قد تكون السمه مرتبطة مع الضبط بإستخدام توضيحات BindingMethods.

يتم إستخدام التعليق التوضيحي مع الفئة ويمكن أن يحتوي على توضيحات BindingMethod متعددة، واحدة لكل دالة أُعيدت تسميتها.

دوال الربط تعتبر تعليقات توضيحية يمكن إضافتها إلى أي فئة في تطبيقك. في المثال التالي، تقترن السمة android:tint بالداله..

 (setImageTintList(ColorStateList ، وليس بدالة ()setTint :

KOTLIN محولات الربط محولات الربط محولات الربط

@BindingMethods(value = [
    BindingMethod(
        type = android.widget.ImageView::class,
        attribute = "android:tint",
        method = "setImageTintList")])

 

JAVA محولات الربط محولات الربط

@BindingMethods({
       @BindingMethod(type = "android.widget.ImageView",
                      attribute = "android:tint",
                      method = "setImageTintList"),
})

 

في معظم الأحيان، لن تحتاج إلى إعادة تسمية دوال الضبط، في فئات إطار عمل الأندرويد. لقد تم تنفيذ السمات بالفعل، بإستخدام إتفاقية الأسم للعثور على الدوال المطابقة تلقائياً.

 

 

توفير منطق مخصص

تحتاج بعض السمات إلى منطق ربط مخصص. على سبيل المثال، لا يوجد دوال ضبط مرتبطة بسمة android:paddingLeft.

بدلاً من ذلك، يتم توفير دالة (setPadding(left, top, right, bottom.

تسمح لك دالة محول الربط الثابت BindingAdapter ذات التعليق التوضيحي بتخصيص كيفية إستدعاء دوال ضبط السمة.

سمات فئات إطار عمل الأندرويد تشتمل على توضيحات BindingAdapter تم إنشاؤها بالفعل. مثال، يعرض المثال التالي محول الربط لسمة paddingLeft:

KOTLIN

@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, padding: Int) {
    view.setPadding(padding,
                view.getPaddingTop(),
                view.getPaddingRight(),
                view.getPaddingBottom())
}

 

JAVA

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
  view.setPadding(padding,
                  view.getPaddingTop(),
                  view.getPaddingRight(),
                  view.getPaddingBottom());
}

 

 

أنواع “المعاملات” الباراميترات مهمة. يحدد المعامل الأول، نوع العرض المقترن بالسمة. المعامل الثاني، يحدد النوع المقبول في تعبير الربط، للسمة المحددة.

تعتبر محولات الربط، مفيدة لأنواع التخصيص الأخرى. مثال، يمكن إستدعاء محمّل مخصص، من التسلسل العامل، لتحميل صورة.

محولات الربط التي قمت بتحديدها، تتجاوز المحولات الإفتراضية، التي يوفرها إطار عمل الأندرويد عند وجود تعارض.

يمكنك أيضاً، إستخدام محولات تتلقى عدة سمات، كما هو موضح في المثال التالي:

KOTLIN

@BindingAdapter("imageUrl", "error")
fun loadImage(view: ImageView, url: String, error: Drawable) {
    Picasso.get().load(url).error(error).into(view)
}

 

JAVA

@BindingAdapter({"imageUrl", "error"})
public static void loadImage(ImageView view, String url, Drawable error) {
  Picasso.get().load(url).error(error).into(view);
}

 

يمكنك إستخدام المحول في مخططك كما هو موضح في المثال التالي.

لاحظ أن drawable/venueError@ تشير إلى مصدر في تطبيقك. إحاطه المصدر بـ {}@ يجعله تعبير ربط صالح.

<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />

 

ملاحظة: تتجاهل مكتبة ربط البيانات النطاقات المخصصة لأغراض المطابقة.

يتم إستدعاء المحول إذا تم إستخدام كلٍ من رابط الصورة imageUrl والخطأ error لكائن ImageView و imageUrl وهي عبارة عن سلسلة وخطأ وهي رسوميه.

إذا كنت تريد إستدعاء المحولات، عند ضبط أي من السمات، فيمكنك تعيين العلامة الإختياريه requireAll الخاصة بالمحول إلى القيمة “خطأ”، كما هو موضح في المثال التالي:

KOTLIN

@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false)
fun setImageUrl(imageView: ImageView, url: String, placeHolder: Drawable) {
    if (url == null) {
        imageView.setImageDrawable(placeholder);
    } else {
        MyImageLoader.loadInto(imageView, url, placeholder);
    }
}

 

JAVA

@BindingAdapter(value={"imageUrl", "placeholder"}, requireAll=false)
public static void setImageUrl(ImageView imageView, String url, Drawable placeHolder) {
  if (url == null) {
    imageView.setImageDrawable(placeholder);
  } else {
    MyImageLoader.loadInto(imageView, url, placeholder);
  }
}

 

ملاحظة: تقوم محولات الربط الخاصة بك بتجاوز محولات ربط البيانات الإفتراضية عندما يكون هناك تعارض.

 

قد تقوم دوال محول الربط بإختيار القيم القديمة في معالجاتها. الدالة التي تأخذ القيم القديمة والجديدة..

يجب أن تعلن عن جميع القيم القديمة للسمات أولاً، متبوعة بالقيم الجديدة، كما هو موضح في المثال التالي:

KOTLIN

@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, oldPadding: Int, newPadding: Int) {
    if (oldPadding != newPadding) {
        view.setPadding(padding,
                    view.getPaddingTop(),
                    view.getPaddingRight(),
                    view.getPaddingBottom())
    }
}

 

JAVA

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
  if (oldPadding != newPadding) {
      view.setPadding(newPadding,
                      view.getPaddingTop(),
                      view.getPaddingRight(),
                      view.getPaddingBottom());
   }
}

 

يمكن إستخدام معالجات الأحداث فقط مع الواجهات أو الفئات التجريدية، بإستخدام دالة تجريديه واحدة، كما هو موضح في المثال التالي:

KOTLIN

@BindingAdapter("android:onLayoutChange")
fun setOnLayoutChangeListener(
        view: View,
        oldValue: View.OnLayoutChangeListener?,
        newValue: View.OnLayoutChangeListener?
) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        if (oldValue != null) {
            view.removeOnLayoutChangeListener(oldValue)
        }
        if (newValue != null) {
            view.addOnLayoutChangeListener(newValue)
        }
    }
}

 

JAVA

@BindingAdapter("android:onLayoutChange")
public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,
       View.OnLayoutChangeListener newValue) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    if (oldValue != null) {
      view.removeOnLayoutChangeListener(oldValue);
    }
    if (newValue != null) {
      view.addOnLayoutChangeListener(newValue);
    }
  }
}

 

إستخدم معالج الأحداث هذا في المخطط الخاص بك كما يلي:

<View android:onLayoutChange="@{() -> handler.layoutChanged()}"/>

 

عندما يكون لدى المستمع عدة دوال، يجب تقسيمه إلى عدة مستمعين. على سبيل المثال، View.OnAttachStateChangeListener لها دالتين:

(onViewAttachedToWindow (View و (onViewDetachedFromWindow (View. توفر المكتبة واجهتين للتمييز بين السمات ومعالجاتها:

KOTLIN

// Translation from provided interfaces in Java:
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
interface OnViewDetachedFromWindow {
    fun onViewDetachedFromWindow(v: View)
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
interface OnViewAttachedToWindow {
    fun onViewAttachedToWindow(v: View)
}

 

JAVA

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewDetachedFromWindow {
  void onViewDetachedFromWindow(View v);
}

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewAttachedToWindow {
  void onViewAttachedToWindow(View v);
}

 

ولأن تغيير مستمع واحد، يمكن أن يؤثر أيضاً على المستمع الآخر، سوف تحتاج إلى محول يعمل مع أياً من السمتين أو مع كلاهما.

يمكنك تعيين requireAll إلى القيمة “خطأ” في التعليق التوضيحي، لتحديد أنه لا يجب تعيين تعبير مرتبط لكل سمة، كما هو موضح في المثال التالي:

KOTLIN

@BindingAdapter(
        "android:onViewDetachedFromWindow",
        "android:onViewAttachedToWindow",
        requireAll = false
)
fun setListener(view: View, detach: OnViewDetachedFromWindow?, attach: OnViewAttachedToWindow?) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
        val newListener: View.OnAttachStateChangeListener?
        newListener = if (detach == null && attach == null) {
            null
        } else {
            object : View.OnAttachStateChangeListener {
                override fun onViewAttachedToWindow(v: View) {
                    attach?.onViewAttachedToWindow(v)
                }

                override fun onViewDetachedFromWindow(v: View) {
                    detach?.onViewDetachedFromWindow(v)
                }
            }
        }

        val oldListener: View.OnAttachStateChangeListener? =
                ListenerUtil.trackListener(view, newListener, R.id.onAttachStateChangeListener)
        if (oldListener != null) {
            view.removeOnAttachStateChangeListener(oldListener)
        }
        if (newListener != null) {
            view.addOnAttachStateChangeListener(newListener)
        }
    }
}

 

JAVA

@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"}, requireAll=false)
public static void setListener(View view, OnViewDetachedFromWindow detach, OnViewAttachedToWindow attach) {
    if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
        OnAttachStateChangeListener newListener;
        if (detach == null && attach == null) {
            newListener = null;
        } else {
            newListener = new OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    if (attach != null) {
                        attach.onViewAttachedToWindow(v);
                    }
                }
                @Override
                public void onViewDetachedFromWindow(View v) {
                    if (detach != null) {
                        detach.onViewDetachedFromWindow(v);
                    }
                }
            };
        }

        OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view, newListener,
                R.id.onAttachStateChangeListener);
        if (oldListener != null) {
            view.removeOnAttachStateChangeListener(oldListener);
        }
        if (newListener != null) {
            view.addOnAttachStateChangeListener(newListener);
        }
    }
}

 

المثال أعلاه أكثر تعقيداً قليلاً، من العادي لأن فئة View تستخدم دوال ()addOnAttachStateChangeListener

و ()methodsOnAttachStateChangeListener بدلاً من دوال الضبط لـ OnAttachStateChangeListener.

تساعد فئة android.databinding.adapters.ListenerUtil في إستمرارية تتبع المستمعين السابقين بحيث يمكن إزالتهم في محول الربط.

من خلال وضع تعليقات على واجهات OnViewDetachedFromWindow و OnViewAttachedToWindow بواسطة (TargetApi(VERSION_CODES.HONEYCOMB_MR1@..

مُنشئ كود ربط البيانات، يعلم أنه يجب إنشاء المستمع فقط، عند التشغيل على أندرويد 3.1 (المستوى 12) وأعلى، نفس الإصدار المدعوم من قبل دالة ()addOnAttachStateChangeListener.

 

 

تحويلات الكائن


 

تحويل الكائن التلقائي

عندما يتم إرجاع كائن object من تعبير الربط، تقوم المكتبة بإختيار الدالة المستخدمة لتعيين قيمة الخاصية.

يتم إرسال “إلقاء” الكائن إلى نوع المعامل من الدالة المختارة.

هذا السلوك مناسب في التطبيقات التي تستخدم فئة ObservableMap لتخزين البيانات، كما هو موضح في المثال التالي: 

<TextView
   android:text='@{userMap["lastName"]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

 

ملاحظة: يمكنك أيضاً الإشارة إلى قيمة في الخريطة بإستخدام التعليق object.key.

على سبيل المثال، يمكن إستبدال  {[“userMap [“lastName}@ من المثال أعلاه بـ  {userMap.lastName}@.

 

يقوم كائن userMap في التعبير بإرجاع قيمة، يتم إرسالها تلقائياً إلى نوع المعامل الموجود في دالة (setText(CharSequence المستخدمة لتعيين..

قيمة السمة android:text. إذا كان نوع المعامل مبهم، فيجب عليك إظهار نوع الإرجاع في التعبير.

 

التحويلات المخصصة

في بعض الحالات، يلزم إجراء تحويل مخصص بين أنواع معينة. مثال، تتوقع سمة الخلفية android:background من طريقة العرض، وجود رسوميات..

ولكن قيمة اللون color المحددة هي عدد صحيح. يوضح المثال التالي سمة تتوقع وجود رسوميات، ولكن تم توفير عدد صحيح بدلاً من ذلك:

<View
   android:background="@{isError ? @color/red : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

 

كلما كان من المتوقع وجود رسوميات وتم إرجاع عدد صحيح يجب تحويل العدد الصحيح int إلى رسوميات لون ColorDrawable.

يمكن إجراء التحويل بإستخدام دالة ثابته، تحتوي على تعليق BindingConversion ، كما يلي:

KOTLIN

@BindingConversion
fun convertColorToDrawable(color: Int) = ColorDrawable(color)

 

JAVA

@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
    return new ColorDrawable(color);
}

 

مع ذلك، أنواع القيم المتوفرة في تعبير الربط، يجب أن تكون ملائمه. لا يمكنك إستخدام أنواع مختلفة في نفس التعبير، كما هو موضح في المثال التالي:

<View
   android:background="@{isError ? @drawable/error : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

 

 


للإطلاع على المقال باللغة الإنجليزية أضغط هنا.

الإعلانات

اترك رد