คุณสามารถใช้ Glass สร้างการโต้ตอบที่สมบูรณ์กับการ์ด เช่น การเลื่อนและภาพเคลื่อนไหว
การเลื่อนการ์ดในกิจกรรม
จอแสดงผลและทัชแพดของ Glass เหมาะอย่างยิ่งสําหรับการแสดงการ์ดที่สลับได้ เช่น ในไทม์ไลน์ของ Glass หากสร้างกิจกรรม คุณจะสร้างเอฟเฟกต์ประเภทเดียวกันได้ด้วยวิดเจ็ต CardScrollView
- ใช้
CardScrollAdapter
เพื่อส่งการ์ดไปยังCardScrollView
คุณจะสร้างลําดับชั้นการแสดงผลมาตรฐานด้วยตนเองหรือใช้คลาสCardBuilder
ก็ได้ - สร้าง
CardScrollView
ที่ใช้CardScrollAdapter
เป็นซัพพลายเออร์สําหรับการ์ด - ตั้งค่ามุมมองเนื้อหากิจกรรมเป็น
CardScrollView
หรือแสดงCardScrollView
ในเลย์เอาต์
ต่อไปนี้เป็นการใช้งานที่ง่ายดายซึ่งจะเลื่อนผ่านการ์ด 3 ใบ
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
คุณจึงนํา Listener Android มาตรฐานมาใช้ได้
- โทรหา
setOnItemClickListener()
ที่รับค่ามาในCardScrollView
- ติดตั้งใช้งานแฮนเดิล
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);
}
});
}
การสร้างการ์ดการเลื่อนแบบเคลื่อนไหว
การ์ดเลื่อนมีภาพเคลื่อนไหว 3 รายการ ได้แก่ การนําทาง การแทรก และการลบ
- แทรกหรือลบการ์ดในการ์ดในตําแหน่งที่ระบุในชุดการ์ด
- โทร
animate()
และใช้ค่าจาก Enum ของ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
มีให้ (โดยทั่วไปจะเป็นการ์ดที่ผู้ใช้มองเห็นได้และการ์ดอื่นๆ บางรายการ)
ด้วยเหตุนี้ การ์ดอาจอยู่ในสถานะใดสถานะหนึ่งใน 4 สถานะต่อไปนี้
- ถูกปลด - มุมมองการเลื่อนของการ์ดไม่จําเป็นต้องใช้การ์ดนี้ในตอนนี้
คุณจะได้รับการแจ้งเตือนโดยใช้เมธอด
onDetachedToWindow()
ของบัตร หากก่อนหน้านี้ได้แนบการ์ดไว้แล้วและปลดการ์ดออก - แนบ - มุมมองการเลื่อนของการ์ดจะขอการ์ดจากอะแดปเตอร์ด้วย
getView()
เนื่องจากการ์ดอยู่ใกล้กับ "เปิดใช้งานแล้ว" คุณจะได้รับการแจ้งเตือนโดยใช้เมธอดonAttachedToWindow()
ของการ์ดเมื่อเกิดเหตุการณ์นี้ - เปิดใช้งาน - ผู้ใช้จะเห็นการ์ดเพียงบางส่วน แต่มุมมองการเลื่อนการ์ดยังไม่ได้ "เลือก" การ์ดที่จะแสดงแก่ผู้ใช้ เมธอด
'isActivated()'
แสดงผล
true
ในกรณีนี้ - เลือกไว้ - การ์ดจะแสดงหน้าจอทั้งหมดของผู้ใช้ การโทร
getSelectedView()
จะแสดงบัตรที่เลือกในปัจจุบัน เมธอดisSelected()
จะแสดงผลเป็น "จริง" ในกรณีนี้
หากสร้างภาพเคลื่อนไหวของมุมมองการ์ดหรือดําเนินการอื่นๆ ที่มีค่าใช้จ่าย ให้เริ่มและหยุดการดําเนินการใน
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; } } }
แก้ไขเมธอด
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)); }