卡片捲軸

透過 Glass,你可以與資訊卡打造豐富的互動功能,例如捲動畫面 和動畫

在活動中捲動資訊卡

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. 呼叫繼承而來的 在「CardScrollView」上的setOnItemClickListener()
  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()通知了 方法。
  • Attached - 資訊卡捲動檢視畫面會要求轉接器以含有 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);
}

實作固定卡片 ID

當系統選擇向使用者顯示的資訊卡時,您可能不行 想變更基礎轉接程式,以影響使用者看到的資訊卡 顯示的結果舉例來說,假設使用者同時查看一張所選資訊卡和一張資訊卡 會從資訊卡左側移除,也就是使用者卡片 可能會移到左側 CardScrollAdapter敬上 根據預設,在發生變化時,就會重新指派 ID 到基礎資料集。

如果理論上指派專屬 ID 是合理的做法, 與基礎資料集的 ID 一致,以避免上述問題。 方法是覆寫 hasStableIds()敬上 並傳回 true。這會指定系統 CardScrollAdapter敬上 各個資料集變更之間,都會維持固定的 ID此外,請將 getItemId()敬上 以傳回轉接器中卡片的正確專屬 ID。 預設實作方式會在轉接程式中傳回資訊卡的位置索引。 在本質上是不穩定的

空白 CardScrollAdapter

當轉接器為空白資料集時,預設檢視畫面為 就是全黑的螢幕如要在這類情況下顯示不同的檢視畫面 請勿使用 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));
    }