شريط تمرير البطاقة

باستخدام Glass، يمكنك إجراء تفاعلات غنية مع بطاقاتك، مثل التمرير والرسوم المتحركة.

تمرير البطاقات في الأنشطة

تعد شاشة الزجاج ولوحة اللمس رائعة لعرض البطاقات القابلة للتمرير، كما هو الحال في المخطط الزمني لـ Glass. إذا كنت تنشئ نشاطًا، يمكنك إنشاء بنفس نوع التأثير مع CardScrollView التطبيق المصغّر.

  1. تنفيذ CardScrollAdapter لتوفير البطاقات CardScrollView يمكنك إنشاء تدرج هرمي عادي لطريقة العرض بنفسك أو استخدام CardBuilder الصف.
  2. إنشاء CardScrollView تستخدم CardScrollAdapter كمورّد للبطاقات.
  3. ضبط طريقة عرض محتوى نشاطك على " CardScrollView أو اعرض CardScrollView في تخطيط.

إليك طريقة تنفيذ بسيطة يتم تمريرها عبر ثلاث بطاقات:

public class CardScrollActivity extends Activity {

    private List<CardBuilder> mCards;
    private CardScrollView mCardScrollView;
    private ExampleCardScrollAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        createCards();

        mCardScrollView = new CardScrollView(this);
        mAdapter = new ExampleCardScrollAdapter();
        mCardScrollView.setAdapter(mAdapter);
        mCardScrollView.activate();
        setContentView(mCardScrollView);
    }

    private void createCards() {
        mCards = new ArrayList<CardBuilder>();

        mCards.add(new CardBuilder(this, CardBuilder.Layout.TEXT)
                .setText("This card has a footer.")
                .setFootnote("I'm the footer!"));

        mCards.add(new CardBuilder(this, CardBuilder.Layout.CAPTION)
                .setText("This card has a puppy background image.")
                .setFootnote("How can you resist?")
                .addImage(R.drawable.puppy_bg));

        mCards.add(new CardBuilder(this, CardBuilder.Layout.COLUMNS)
                .setText("This card has a mosaic of puppies.")
                .setFootnote("Aren't they precious?")
                .addImage(R.drawable.puppy_small_1);
                .addImage(R.drawable.puppy_small_2);
                .addImage(R.drawable.puppy_small_3));
    }

    private class ExampleCardScrollAdapter extends CardScrollAdapter {

        @Override
        public int getPosition(Object item) {
            return mCards.indexOf(item);
        }

        @Override
        public int getCount() {
            return mCards.size();
        }

        @Override
        public Object getItem(int position) {
            return mCards.get(position);
        }

        @Override
        public int getViewTypeCount() {
            return CardBuilder.getViewTypeCount();
        }

        @Override
        public int getItemViewType(int position){
            return mCards.get(position).getItemViewType();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            return mCards.get(position).getView(convertView, parent);
        }
    }
}

التفاعل مع البطاقات القابلة للتمرير

منذ CardScrollView يمتد إلى AdapterView يمكنكم تنفيذ مستمعي Android العاديين.

  1. طلب البيانات المُكتسَبة setOnItemClickListener() على CardScrollView.
  2. تنفيذ onItemClick() معالِج حدث النقر.

في ما يلي إضافة إلى المثال السابق لتشغيل صوت نقر عند النقر على بطاقة:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        setupClickListener();
        setContentView(mCardScrollView);
    }

    private void setupClickListener() {
        mCardScrollView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                am.playSoundEffect(Sounds.TAP);
            }
        });
    }

بطاقات التمرير المتحركة

تتوفر ثلاث رسوم متحركة لتمرير البطاقات: التنقل والإدراج والحذف.

  1. تنفيذ إجراء إدراج أو حذف على بطاقة في موضع محدّد في مجموعة البطاقات
  2. اتصل animate() واستخدِم قيمة من التعداد CardScrollView.Animation.
  3. لعرض رسم متحرك أكثر سلاسة، أزل أي إشارات إلى notifyDataSetChanged() animate() الطريقة التي تعالج بها طريقة عرض مجموعة البيانات.

    private class ExampleCardScrollAdapter extends CardScrollAdapter {
        ...
    
        // Inserts a card into the adapter, without notifying.
        public void insertCardWithoutNotification(int position, CardBuilder card) {
            mCards.add(position, card);
        }
    }
    
    private void insertNewCard(int position, CardBuilder card) {
        // Insert new card in the adapter, but don't call
        // notifyDataSetChanged() yet. Instead, request proper animation
        // to inserted card from card scroller, which will notify the
        // adapter at the right time during the animation.
        mAdapter.insertCardWithoutNotification(position, card);
        mCardScrollView.animate(position, CardScrollView.Animation.INSERTION);
    }
    

نصائح بشأن الأداء والتنفيذ لتمرير البطاقات

ضع في اعتبارك الآثار المترتبة على التصميم والأداء التالية عند إنشاء وتمرير البطاقات.

مراحل نشاط البطاقة

لتحسين الأداء، يجب إضافة CardScrollView فقط مجموعة فرعية من البطاقات التي CardScrollAdapter (بشكل عام، تلك التي تظهر للمستخدم، وغير ذلك). ولهذا السبب، يمكن أن تكون البطاقة في أي من الحالات العامة الأربع التالية:

  • تم فصلها: لا يحتاج العرض بالتمرير إلى هذه البطاقة في الوقت الحالي. يتم إشعارك من خلال onDetachedToWindow() الخاص بالبطاقة. إذا تم إرفاق بطاقة من قبل ثم فصلها.
  • مرفقة - يطلب عرض التمرير في البطاقة البطاقة من المحوّل getView()، لأنّ البطاقة على وشك أن "يتم تفعيلها". ويتم إشعارك باستخدام طريقة onAttachedToWindow() الخاصة بالبطاقة عند حدوث ذلك.
  • نشطة - تظهر البطاقة جزئيًا للمستخدم، ولكن يتم تمرير البطاقة لم يتم "تحديد" طريقة العرض البطاقة لعرضها للمستخدم. تشير رسالة الأشكال البيانية 'isActivated()' تعرض true في هذه الحالة.
  • محددة: تشغل البطاقة حساب المستخدم الشاشة بأكملها. يؤدي الاتصال بالرقم getSelectedView() إلى عرض البطاقة المحدّدة حاليًا. تعرض الطريقة isSelected() true في هذه الحالة.

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

إعادة تدوير البطاقات

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

للاستفادة من إمكانية إعادة تدوير البطاقات، عليك تنفيذ getItemViewType()، getViewTypeCount(), وgetView() طريقة CardScrollAdapter الصف. يمكنك بعد ذلك استخدام بعض الطرق الملائمة في CardBuilder. تنفيذ إعادة التدوير في CardScrollAdapter، كما هو الحال في المثال التالي:

private List<CardBuilder> mCards;
...
/**
 * Returns the number of view types for the CardBuilder class. The
 * CardBuilder class has a convenience method that returns this value for
 * you.
 */
@Override
public int getViewTypeCount() {
    return CardBuilder.getViewTypeCount();
}

/**
 * Returns the view type of this card, so the system can figure out
 * if it can be recycled. The CardBuilder.getItemViewType() method
 * returns it's own type.
 */
@Override
public int getItemViewType(int position){
    return mCards.get(position).getItemViewType();
}

/**
 * When requesting a card from the adapter, recycle the view if possible.
 * The CardBuilder.getView() method automatically recycles the convertView
 * it receives, if possible, or creates a new view if convertView is null or
 * of the wrong type.
 */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    return  mCards.get(position).getView(convertView, parent);
}

تنفيذ معرّفات البطاقة الثابتة

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

إذا كان من المنطقي تخصيص معرّفات فريدة لبطاقاتك، يمكنك معرّف ثابت في مجموعة البيانات الأساسية لمنع حدوث المشكلة المذكورة أعلاه. لإجراء ذلك، عليك إلغاء hasStableIds() وإرجاع true. يحدد هذا للنظام أن CardScrollAdapter يحتفظ بمعرّفات ثابتة على مستوى تغييرات مجموعات البيانات. بالإضافة إلى ذلك، نفِّذ getItemId() لإرجاع المعرّف الفريد المناسب للبطاقات في المحوّل. يُرجع التنفيذ الافتراضي فهرس موضع البطاقة في المحوّل، وهو بطبيعتها غير مستقرة.

محوِّل تمرير البطاقة الفارغة

عندما يكون لديك مجموعة بيانات فارغة للمحوّلات، يكون العرض التلقائي هو إظهار شاشة سوداء. إذا أردت إظهار طريقة عرض مختلفة في هذه الحالات، لا تستخدم setEmptyView(). بدلاً من ذلك، أنشِئ بطاقة واحدة في CardScrollAdapter.

ملاحظات حول السحب الأفقي

يمكنك استخدام العديد من أدوات الغمس المُدمَجة في Glass ملاحظات عند التمرير للخلف إعادة التوجيه لا تقوم بتنفيذ أي إجراء. على سبيل المثال، يمكنك الاطلاع على هذه الملاحظات عندما التمرير السريع بعد التقاط صورة.

إذا كان الغطس لا يستخدم إيماءات التمرير السريع الأفقي لتنفيذ الخاصة بالتطبيق، توفر تأثير الجذب هذا من خلال إحاطة التخطيط داخل CardScrollView تحتوي على بطاقة واحدة.

  1. انسخ فئة المساعد التالية إلى مشروعك:

    public class TuggableView extends CardScrollView {
    
        private final View mContentView;
    
        /**
         * Initializes a TuggableView that uses the specified layout
         * resource for its user interface.
         */
        public TuggableView(Context context, int layoutResId) {
            this(context, LayoutInflater.from(context)
                    .inflate(layoutResId, null));
        }
    
        /**
         * Initializes a TuggableView that uses the specified view
         * for its user interface.
         */
        public TuggableView(Context context, View view) {
            super(context);
    
            mContentView = view;
            setAdapter(new SingleCardAdapter());
            activate();
        }
    
        /**
         * Overridden to return false so that all motion events still
         * bubble up to the activity's onGenericMotionEvent() method after
         * they are handled by the card scroller. This allows the activity
         * to handle TAP gestures using a GestureDetector instead of the
         * card scroller's OnItemClickedListener.
         */
        @Override
        protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
            super.dispatchGenericFocusedEvent(event);
            return false;
        }
    
        /** Holds the single "card" inside the card scroll view. */
        private class SingleCardAdapter extends CardScrollAdapter {
    
            @Override
            public int getPosition(Object item) {
                return 0;
            }
    
            @Override
            public int getCount() {
                return 1;
            }
    
            @Override
            public Object getItem(int position) {
                return mContentView;
            }
    
            @Override
            public View getView(int position, View recycleView,
                    ViewGroup parent) {
                return mContentView;
            }
        }
    }
    
  2. عدِّل طريقة onCreate في نشاطك لعرض CardScrollView الذي يحتوي على التخطيط الخاص بك.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        // was: setContentView(R.layout.main_activity);
        setContentView(new TuggableView(this, R.layout.main_activity));
    }