透過 Glass,你可以與資訊卡打造豐富的互動功能,例如捲動畫面 和動畫
在活動中捲動資訊卡
Glass 螢幕和觸控板非常適合顯示滑動式卡片。
就像 Glass 時間軸一樣如要建構活動,您可以建立
相同效果類型
CardScrollView
敬上
- 實作
CardScrollAdapter
敬上 為卡片提供CardScrollView
。 您可以自行建立標準檢視區塊階層,也可以使用CardBuilder
敬上 類別 - 撰寫
CardScrollView
敬上 使用CardScrollAdapter
。 做為卡片的供應商 - 將活動的內容檢視設為
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 事件監聽器
- 呼叫繼承而來的
在「
CardScrollView
」上的setOnItemClickListener()
。 - 實作
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);
}
});
}
為捲動資訊卡建立動畫
捲動資訊卡有三種動畫可用:瀏覽、插入和刪除。
- 針對資訊卡集中指定位置的資訊卡實作插入或刪除動作。
- 致電
animate()
敬上 並使用CardScrollView.Animation
列舉中的值。 為了顯示更流暢的動畫,請移除
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
敬上
當中包含一張資訊卡
將下列輔助類別複製到專案中:
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; } } }
修改活動中的
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)); }