Kart Kaydırma Aracı

Glass ile kartlarınızla kaydırma ve animasyonlar gibi zengin etkileşimler oluşturabilirsiniz.

Etkinliklerdeki kaydırma kartları

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

  1. CardScrollView'e kart sağlamak için CardScrollAdapter uygulayın. Standart bir görünüm hiyerarşisini kendiniz 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 olarak ayarlayın veya CardScrollView öğesini bir düzen içinde görüntüleyin.

Aşağıda, üç kart arasında geçiş yapan basit bir uygulama verilmiştir:

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şimde bulunma

CardScrollView, AdapterView uzantısına sahip olduğundan standart Android işleyicilerini uygulayabilirsiniz.

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

Önceki örneğe ait olan ve bir karta dokunduğunuzda dokunma sesi çalan bir uzantıyı burada görebilirsiniz:

    @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ı için kullanılabilecek üç animasyon vardır: Gezinme, Ekleme ve Silme.

  1. Kart grubunda belirtilen bir konuma karta ekleme veya silme işlemi uygulayın.
  2. animate() çağrısı yapın ve CardScrollView.Animation sıralamasındaki bir değeri kullanın.
  3. Daha düzgün bir animasyon görüntülemek için notifyDataSetChanged() başvurularını kaldırın. animate() yöntemi, veri kümesi görünümünüzü günceller.

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

Kaydırma kartları için performans ve uygulama ipuçları

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

Kartın yaşam döngüsü

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

  • Ayrıldı: Kart kaydırma görünümünde şu anda bu kart gerekli değildir. Daha önce kart takılıp çıkarılmışsa kartın onDetachedToWindow() yöntemi üzerinden bilgilendirilirsiniz.
  • Eklendi: Kart "etkinleştirilmeye" yakın olduğu için kart kaydırma görünümü, adaptörden getView() ile kartı ister. Böyle bir durumda, kartın onAttachedToWindow() yöntemi üzerinden bilgilendirilirsiniz.
  • Etkinleştirildi: Kart kullanıcı tarafından kısmen görülebilir, ancak kart kaydırma görünümünde kullanıcıya gösterilecek kartı "seçmemiştir". Bu durumda 'isActived()' yöntemi true değerini döndürür.
  • Seçili: Kart, kullanıcının ekranın tamamını kaplar. getSelectedView() çağrıldığında, 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 maliyetli işlemler gerçekleştiriyorsanız kaynaklardan tasarruf etmek için onAttachedToWindow() ve onDetachedToWindow() uygulamalarında işlemleri başlatıp durdurun.

Kart geri dönüşümü

Bir kart, takılıp çıkarıldıktan sonra çıkarıldığında kartla ilişkilendirilen görünüm nesnesi geri dönüştürülebilir ve takılı olan bir kart tarafından kullanılabilir. Görünümlerin güncellenmiş bilgilerle geri dönüştürülmesi, yeni görünümler 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, CardScrollAdapter hesabınızda geri dönüşümü uygulamak için CardBuilder sınıfındaki bazı kolaylık yöntemlerini aşağıdaki örnekte gösterildiği gibi 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 kimlikleri uygulama

Bir kart seçilip kullanıcılara gösterildiğinde, temel bağdaştırıcıda yapılan değişikliklerin, kullanıcıların o anda gördüğü kartı etkilemesini istemeyebilirsiniz. Örneğin, bir kullanıcı seçili bir kartı görüntülüyorsa ve bu kartın sol tarafından kaldırılırsa kullanıcının görüntülemekte olduğu kart sola kayabilir. Bunun nedeni, değişiklik gerçekleştiğinde CardScrollAdapter tarafından temel veri kümesine varsayılan olarak yeniden kimlik atanmasıdır.

Kartlarınıza benzersiz kimlikler atamak mantıksal olarak anlamlıysa yukarıda belirtilen sorunu önlemek için temel veri kümesinde tutarlı bir kimlik sağlayabilirsiniz. Bunu yapmak için hasStableIds() kodunu geçersiz kılın ve true değerini döndürün. Bu, CardScrollAdapter'ın sisteme, veri kümesi değişikliklerinde kararlı kimlikler koruduğunu belirtir. Ayrıca, adaptörünüzdeki kartlar için uygun benzersiz kimliği döndürmek amacıyla getItemId() kodunu uygulayın. Varsayılan uygulama, kendiliğinden kararsız olan adaptörde kartın konum dizinini döndürür.

Card ScrollAdapter boş

Bağdaştırıcılar 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 hesabınızda tek bir kart oluşturun.

Yatay çekme geri bildirimi

Glass'taki yerleşik pek çok özellikte, geri ve ileri kaydırma sırasında herhangi bir işlem yapılmasına gerek kalmadan"çekme" geri bildirimi sağlanır. Örneğin, fotoğraf çektikten sonra hızlıca kaydırma işleminde bu geri bildirimi görebilirsiniz.

Yoğunlaşma sürecinde uygulamaya özel işlevleri gerçekleştirmek için yatay kaydırma hareketleri kullanılmıyorsa bu çekme efektini, düzeninizi bir kart içeren bir CardScrollView içine sarmalayı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ğinizde onCreate yöntemini değiştirerek düzeninizi içeren CardScrollView öğesini görüntüleyin.

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