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()
และใช้ค่าจาก enumCardScrollView.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()
เพื่อส่งคืนรหัสที่ไม่ซ้ำกันที่เหมาะสมสำหรับบัตรในอะแดปเตอร์ของคุณ
การใช้งานเริ่มต้นจะแสดงดัชนีตำแหน่งของการ์ดในอะแดปเตอร์
ซึ่งไม่เสถียร
Card ScrollAdapter ว่างเปล่า
เมื่อคุณมีชุดข้อมูลที่ว่างเปล่าสำหรับอะแดปเตอร์ มุมมองเริ่มต้นจะแสดง
หน้าจอสีดำ หากคุณต้องการแสดงมุมมองอื่นในกรณีเหล่านี้
ไม่ใช้ 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)); }