Kart Kaydırma Aracı

Glass ile kartlarınızla zengin etkileşimler oluşturabilirsiniz. Örneğin, kaydırma ve animasyon gibi.

Etkinliklerde kartlar

Glass ekran ve dokunmatik alan, Glass zaman çizelgesi gibi kaydırılabilir kartları görüntülemek için idealdir. Bir etkinlik oluşturuyorsanız CardScrollView widget'ıyla aynı türde efekt oluşturabilirsiniz.

  1. CardScrollView kartına kart sağlamak için CardScrollAdapter uygulayın. Kendiniz için standart bir görünüm hiyerarşisi oluşturabilir veya CardBuilder sınıfını kullanabilirsiniz.
  2. Kart tedarikçisi olarak CardScrollAdapter kullanan bir CardScrollView oluşturun.
  3. Etkinliğinizin içerik görünümünü CardScrollView olacak şekilde ayarlayın veya CardScrollView simgesini bir düzende görüntüleyin.

Üç kart arasında gezinen basit bir uygulamayı burada görebilirsiniz:

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

Kaydırma kartlarıyla etkileşim

CardScrollView AdapterView sınırlandığından standart Android dinleyicilerini uygulayabilirsiniz.

  1. Devralınan setOnItemClickListener() numarasını CardScrollView cihazınızda çağırın.
  2. Dokunma etkinliği için bir onItemClick() işleyici uygulayın.

Önceki örneğin, bir karta dokunduğunuzda "dokunma sesi" çalan bir uzantısı şu şekildedir:

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

Kaydırma kartlarına animasyon ekleme

Kaydırma kartlarında kullanılabilecek üç animasyon vardır: Gezinme, Ekleme ve Silme.

  1. Bir kartta kart kümesinde belirtilen bir konuma ekleme veya silme işlemi uygulayın.
  2. animate() değerini çağırın ve CardScrollView.Animation sıralamasından bir değer kullanın.
  3. Daha akıcı bir animasyon görüntülemek için notifyDataSetChanged() referansını kaldırın. Veri kümesi görünümünüzün güncellenmesinde animate() yöntemi kullanılır.

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

Kartları kaydırmaya ilişkin performans ve uygulama ipuçları

Kart kaydırma kartları oluştururken aşağıdaki tasarım ve performans sonuçlarını göz önünde bulundurun.

Kart yaşam döngüsü

CardScrollView, performansı artırmak için yalnızca CardScrollAdapter tarafından sağlanan kartların (yalnızca kullanıcı tarafından görülebilenler ve birkaç kart daha) bir alt kümesini yükler. Bu nedenle, kart aşağıdaki dört genel durumdan birinde olabilir:

  • Ayrıldı: Kart kaydırma görünümünde şu anda bu karta ihtiyaç yoktur. Bir kart daha önce eklendiyse ve çıkarıldıysa kartın onDetachedToWindow() yöntemiyle bilgilendirilirsiniz.
  • Ekli: Kart kaydırma görünümü, kart "etkinleştirilmeye" yakın olduğundan adaptörden getView() ile birlikte kartı ister. Bu durumda kartın onAttachedToWindow() yöntemiyle bilgilendirilirsiniz.
  • Etkinleştirildi - Kullanıcı kartı kısmen görebilir, ancak kart kaydırma görünümü kullanıcıya gösterilecek kartı "seçmedi". Bu durumda 'isActivated()' yöntemi true değerini döndürür.
  • Seçildi: Kart, kullanıcının tüm ekranını kaplar. getSelectedView() numaralı telefonu seçtiğinizde şu anda seçili olan kart döndürülür. Bu durumda isSelected() yöntemi "true" değerini döndürür.

Kartınızın görünümünü canlandırıyor veya başka yüksek maliyetli işlemler yapıyorsanız kaynakları kaydetmek için onAttachedToWindow() ve onDetachedToWindow()'teki işlemleri başlatın ve durdurun.

Kart geri dönüşümü

Bir kart, ekleme işleminden ayrılıp ayrıldığında, kartla ilişkilendirilen görünüm nesnesi geri dönüştürülebilir ve eklenen bir kart tarafından kullanılabilir. Güncellenen bilgilerle geri dönüşüm elde etmek, yeni görüntüleme oluşturmaktan çok daha verimlidir.

Kart geri dönüşümünden yararlanmak için CardScrollAdapter sınıfının getItemViewType(), getViewTypeCount() ve getView() yöntemlerini uygulayın. Ardından, aşağıdaki örnekte olduğu gibi, CardScrollAdapter uygulamanızda geri dönüşüm uygulamak için CardBuilder sınıfındaki bazı kolaylık yöntemlerini kullanırsınız:

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

Kararlı kart kimliklerini uygulama

Bir kart seçilip kullanıcılara gösterilirken temel adaptörde yapılan değişikliklerin, kullanıcıların o anda gördüğü kartı etkilemesini istemeyebilirsiniz. Örneğin, kullanıcı belirli bir kartı görüntülediğinde ve kartın solundaki bir kart kaldırılırsa kullanıcının görüntülediği kart, CardScrollAdapter'te varsayılan olarak kimliklerin temeldeki veri kümesine yeniden kimlik atanmasından dolayı varsayılan olarak sola kaydırılabilir.

Kartlarınıza benzersiz kimlikler atamak mantıksal olarak mantıklıysa yukarıda bahsedilen sorunu önlemek için temel veri kümesinde tutarlı bir kimlik tutabilirsiniz. Bunu yapmak için hasStableIds() değerini geçersiz kılın ve true değerini döndürün. Bu, sistem için CardScrollAdapter veri kümesi değişikliklerinde sabit kimliklere sahip olduğunu belirtir. Ayrıca, adaptörünüzdeki kartlar için uygun benzersiz kimliği döndürmek üzere getItemId() kodunu uygulayın. Varsayılan uygulama, bağdaştırıcıda kartın konum dizinini döndürür ve bu özellik doğası gereği kararsızdır.

Boş Card ScrollAdapter

Adaptörler için boş bir veri kümeniz olduğunda varsayılan görünüm siyah ekran göstermektir. Bu durumlarda farklı bir görünüm göstermek istiyorsanız setEmptyView() kullanmayın. Bunun yerine, CardScrollAdapter'nda tek bir kart oluşturun.

Yatay eğimli geri bildirim

Glass'taki pek çok yerleşik ayar, geri ve ileri kaydırdığınızda herhangi bir işlem yapılmadan geri çekilme sağlar. Örneğin, fotoğraf çektikten sonra ekranı kaydırırken bu geri bildirimi görebilirsiniz.

Dalganız uygulamaya özgü işlevleri gerçekleştirmek için yatay kaydırma hareketlerini kullanmıyorsa düzeninizi tek kart içeren bir CardScrollView içine sarmalayarak bu çekme efektini sağlayın.

  1. Aşağıdaki yardımcı sınıfı projenize kopyalayın:

    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. Etkinliğinizdeki onCreate yöntemini, düzeninizi içeren CardScrollView değerini görüntüleyecek şekilde değiştirin.

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