ฉันจะสร้างรายการที่เมื่อคุณมาถึงจุดสิ้นสุดของรายการที่ฉันได้รับแจ้งเพื่อให้ฉันสามารถโหลดรายการเพิ่มเติมได้อย่างไร
ฉันจะสร้างรายการที่เมื่อคุณมาถึงจุดสิ้นสุดของรายการที่ฉันได้รับแจ้งเพื่อให้ฉันสามารถโหลดรายการเพิ่มเติมได้อย่างไร
คำตอบ:
ทางออกหนึ่งคือการใช้OnScrollListener
และทำการเปลี่ยนแปลง (เช่นการเพิ่มรายการ ฯลฯ ) ไปยังสถานะListAdapter
ที่สะดวกในonScroll
วิธีการ
ต่อไปนี้ListActivity
จะแสดงรายการของจำนวนเต็มเริ่มต้นด้วย 40 เพิ่มรายการเมื่อผู้ใช้เลื่อนไปที่ส่วนท้ายของรายการ
public class Test extends ListActivity implements OnScrollListener {
Aleph0 adapter = new Aleph0();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(adapter);
getListView().setOnScrollListener(this);
}
public void onScroll(AbsListView view,
int firstVisible, int visibleCount, int totalCount) {
boolean loadMore = /* maybe add a padding */
firstVisible + visibleCount >= totalCount;
if(loadMore) {
adapter.count += visibleCount; // or any other amount
adapter.notifyDataSetChanged();
}
}
public void onScrollStateChanged(AbsListView v, int s) { }
class Aleph0 extends BaseAdapter {
int count = 40; /* starting amount */
public int getCount() { return count; }
public Object getItem(int pos) { return pos; }
public long getItemId(int pos) { return pos; }
public View getView(int pos, View v, ViewGroup p) {
TextView view = new TextView(Test.this);
view.setText("entry " + pos);
return view;
}
}
}
คุณควรใช้เธรดแยกต่างหากสำหรับการดำเนินการที่ต้องใช้เวลานาน (เช่นการโหลดเว็บข้อมูล) และอาจต้องการระบุความคืบหน้าในรายการสุดท้าย (เช่นตลาดหรือแอพ gmail)
firstVisible + visibleCount >= totalCount
ตรงตามหลายครั้งด้วยการเรียกหลายครั้งไปยังผู้ฟัง หากฟังก์ชั่นโหลดมากขึ้นเป็นคำขอของเว็บ (ส่วนใหญ่จะเป็นฟังก์ชั่น) ให้เพิ่มการตรวจสอบอีกครั้งว่ามีคำขอเกิดขึ้นหรือไม่ ในอีกทางหนึ่งตรวจสอบว่าจำนวนรวมไม่เท่ากับจำนวนรวมก่อนหน้าเนื่องจากเราไม่ต้องการคำขอหลายรายการสำหรับจำนวนรายการเดียวกันในรายการ
แค่ต้องการมีส่วนร่วมในการแก้ปัญหาที่ฉันใช้กับแอพ
มันขึ้นอยู่กับOnScrollListener
อินเทอร์เฟซ แต่ฉันพบว่ามันมีประสิทธิภาพการเลื่อนที่ดีขึ้นมากในอุปกรณ์ระดับล่างเนื่องจากไม่มีการคำนวณจำนวนการมองเห็น / การนับรวมที่ดำเนินการระหว่างการเลื่อน
ListFragment
หรือListActivity
ใช้ของคุณOnScrollListener
เพิ่มวิธีการต่อไปนี้ลงในคลาสนั้น:
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
//leave this empty
}
@Override
public void onScrollStateChanged(AbsListView listView, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
if (listView.getLastVisiblePosition() >= listView.getCount() - 1 - threshold) {
currentPage++;
//load more list items:
loadElements(currentPage);
}
}
}
โดยที่currentPage
หน้าของแหล่งข้อมูลของคุณที่ควรถูกเพิ่มลงในรายการของคุณและthreshold
เป็นจำนวนรายการ (นับจากตอนท้าย) ที่ควรจะเรียกกระบวนการโหลดหากมองเห็นได้ ถ้าคุณตั้งค่าthreshold
ไป0
ตัวอย่างเช่นผู้ใช้มีการเลื่อนไปที่ปลายสุดของรายการเพื่อโหลดรายการอื่น ๆ
(ไม่บังคับ) ดังที่คุณเห็น "การตรวจสอบโหลดมากขึ้น" จะถูกเรียกเมื่อผู้ใช้หยุดเลื่อน listView.addFooterView(yourFooterView)
เพื่อปรับปรุงการใช้งานคุณอาจขยายและเพิ่มตัวบ่งชี้ที่โหลดไปยังจุดสิ้นสุดของรายการผ่านทาง ตัวอย่างหนึ่งสำหรับมุมมองส่วนท้ายดังกล่าว:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/footer_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp" >
<ProgressBar
android:id="@+id/progressBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/progressBar1"
android:padding="5dp"
android:text="@string/loading_text" />
</RelativeLayout>
(ไม่บังคับ)สุดท้ายลบตัวบ่งชี้การโหลดนั้นโดยการโทรlistView.removeFooterView(yourFooterView)
หากไม่มีรายการหรือหน้า
ListFragment
เช่นกันโดยไม่มีปัญหา - เพียงทำตามแต่ละขั้นตอนข้างต้นและคุณจะสบายดี;) หรือคุณสามารถให้ข้อความแสดงข้อผิดพลาด?
getListView().setOnScrollListener(this)
คุณสามารถตรวจสอบท้ายของรายการด้วยความช่วยเหลือของonScrollListenerรหัสการทำงานจะนำเสนอดังต่อไปนี้:
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (view.getAdapter() != null && ((firstVisibleItem + visibleItemCount) >= totalItemCount) && totalItemCount != mPrevTotalItemCount) {
Log.v(TAG, "onListEnd, extending list");
mPrevTotalItemCount = totalItemCount;
mAdapter.addMoreData();
}
}
อีกวิธีในการทำเช่นนั้น (อะแดปเตอร์ภายใน) มีดังต่อไปนี้:
public View getView(int pos, View v, ViewGroup p) {
if(pos==getCount()-1){
addMoreData(); //should be asynctask or thread
}
return view;
}
addMoreData()
โปรดทราบว่าวิธีการนี้จะถูกเรียกว่าหลายครั้งดังนั้นคุณจำเป็นต้องเพิ่มเงื่อนไขอื่นเพื่อป้องกันการหลายสายของ
เมื่อคุณเพิ่มองค์ประกอบทั้งหมดลงในรายการโปรดโทรinformDataSetChanged ()ภายในอะแดปเตอร์ของคุณเพื่ออัปเดตมุมมอง (ควรเรียกใช้บนเธรด UI - runOnUiThread )
getView
นอกเหนือจากมุมมองกลับมาใน ตัวอย่างเช่นคุณไม่รับประกันว่าpos
ผู้ใช้จะดู มันอาจเป็นเพียงเครื่องมือวัด ListView
ที่Ognyan Bankov GitHub
ฉันพบวิธีที่ง่ายและทำงาน!
มันทำให้การใช้งานVolley HTTP library
ที่ทำให้เครือข่ายสำหรับแอพ Android ง่ายขึ้นและที่สำคัญที่สุดคือเร็วขึ้น วอลเล่ย์มีให้บริการผ่านที่เก็บ AOSP แบบเปิด
รหัสที่กำหนดแสดงให้เห็นถึง:
สำหรับความมั่นคงในอนาคตฉันคดเคี้ยว repo
นี่คือวิธีการแก้ปัญหาที่ทำให้การแสดงมุมมองการโหลดในตอนท้ายของ ListView ง่ายขึ้นในขณะที่กำลังโหลด
คุณสามารถดูชั้นเรียนได้ที่นี่:
https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - ช่วยให้สามารถใช้งานได้ ฟีเจอร์โดยไม่ต้องขยายจาก SimpleListViewWithLoadingIndicator
https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - ผู้ฟังที่เริ่มโหลดข้อมูลเมื่อผู้ใช้ ใกล้จะถึงด้านล่างของ ListView
https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - The EndlessListView คุณสามารถใช้คลาสนี้โดยตรงหรือขยายออกไป
อาจจะช้าไปหน่อย แต่วิธีแก้ปัญหาต่อไปนี้เกิดขึ้นมีประโยชน์มากในกรณีของฉัน ในทุกสิ่งที่คุณต้องทำคือเพิ่มใน ListView ของคุณFooter
และสร้างมันaddOnLayoutChangeListener
ขึ้นมา
http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)
ตัวอย่างเช่น:
ListView listView1 = (ListView) v.findViewById(R.id.dialogsList); // Your listView
View loadMoreView = getActivity().getLayoutInflater().inflate(R.layout.list_load_more, null); // Getting your layout of FooterView, which will always be at the bottom of your listview. E.g. you may place on it the ProgressBar or leave it empty-layout.
listView1.addFooterView(loadMoreView); // Adding your View to your listview
...
loadMoreView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Log.d("Hey!", "Your list has reached bottom");
}
});
เหตุการณ์นี้จะเริ่มขึ้นเมื่อมีส่วนท้ายปรากฏให้เห็นและใช้งานได้อย่างมีเสน่ห์
กุญแจสำคัญของปัญหานี้คือการตรวจสอบเหตุการณ์ที่เกิดขึ้นโหลดเริ่มคำขอ async สำหรับข้อมูลแล้วอัปเดตรายการ นอกจากนี้ยังจำเป็นต้องใช้อะแดปเตอร์พร้อมตัวบ่งชี้การโหลดและอุปกรณ์ตกแต่งอื่น ในความเป็นจริงปัญหามีความซับซ้อนมากในบางกรณีมุม เพียงOnScrollListener
การนำไปปฏิบัติไม่เพียงพอเพราะบางครั้งรายการไม่เต็มหน้าจอ
ฉันได้เขียนแพ็คเกจส่วนบุคคลที่รองรับรายการที่ไม่มีที่สิ้นสุดRecyclerView
และยังมีการใช้งานตัวโหลด async AutoPagerFragment
ซึ่งทำให้ง่ายต่อการรับข้อมูลจากแหล่งที่มาหลายหน้า มันสามารถโหลดหน้าใด ๆ ที่คุณต้องการในRecyclerView
เหตุการณ์ที่กำหนดเองไม่เพียง แต่หน้าถัดไป
นี่คือที่อยู่: https://github.com/SphiaTower/AutoPagerRecyclerManager
ทางออกที่ดีที่สุดที่ฉันได้เห็นคือในไลบรารีFastAdapterสำหรับมุมมองของนักรีไซเคิล EndlessRecyclerOnScrollListener
แต่ก็มี
นี่คือตัวอย่างการใช้งาน: EndlessScrollListActivity
เมื่อฉันใช้มันสำหรับรายการเลื่อนที่ไม่มีที่สิ้นสุดฉันได้ตระหนักว่าการตั้งค่านั้นแข็งแกร่งมาก ฉันขอแนะนำอย่างแน่นอน
ฉันทำงานในโซลูชันอื่นที่คล้ายกันมาก แต่ฉันใช้footerView
เพื่อให้ผู้ใช้สามารถดาวน์โหลดองค์ประกอบเพิ่มเติมที่คลิกfooterView
ฉันใช้ "เมนู" ซึ่งแสดงอยู่ด้านบนListView
และด้านล่างของ มุมมองพาเรนต์ "เมนู" นี้ซ่อนด้านล่างของListView
ดังนั้นเมื่อการlistView
เลื่อนเมนูหายไปและเมื่อสถานะการเลื่อนไม่ได้ใช้งานเมนูจะปรากฏขึ้นอีกครั้ง แต่เมื่อผู้ใช้เลื่อนไปยังจุดสิ้นสุดlistView
ฉัน "ถาม" ถึง ทราบว่าfooterView
มีการแสดงในกรณีนั้นหรือไม่เมนูจะไม่ปรากฏขึ้นและผู้ใช้สามารถเห็นการfooterView
โหลดเนื้อหาเพิ่มเติม ที่นี่รหัส:
ความนับถือ.
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
if(scrollState == SCROLL_STATE_IDLE) {
if(footerView.isShown()) {
bottomView.setVisibility(LinearLayout.INVISIBLE);
} else {
bottomView.setVisibility(LinearLayout.VISIBLE);
} else {
bottomView.setVisibility(LinearLayout.INVISIBLE);
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
});
ฉันรู้ว่ามันเป็นคำถามเก่าและโลก Android ได้ย้ายไปที่ RecyclerViews เป็นส่วนใหญ่ แต่สำหรับใครที่สนใจคุณอาจพบว่าห้องสมุดนี้น่าสนใจมาก
มันใช้ BaseAdapter ที่ใช้กับ ListView เพื่อตรวจสอบเมื่อรายการถูกเลื่อนไปยังรายการสุดท้ายหรือเมื่อมันถูกเลื่อนออกไปจากรายการสุดท้าย
มันมาพร้อมกับโครงการตัวอย่าง (รหัสกิจกรรมเกือบ 100 บรรทัด) ที่สามารถใช้เพื่อให้เข้าใจได้อย่างรวดเร็วว่าทำงานอย่างไร
การใช้งานง่าย:
class Boy{
private String name;
private double height;
private int age;
//Other code
}
อะแดปเตอร์สำหรับเก็บวัตถุ Boy จะมีลักษณะดังนี้:
public class BoysAdapter extends EndlessAdapter<Boy>{
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent
.getContext());
holder = new ViewHolder();
convertView = inflater.inflate(
R.layout.list_cell, parent, false);
holder.nameView = convertView.findViewById(R.id.cell);
// minimize the default image.
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Boy boy = getItem(position);
try {
holder.nameView.setText(boy.getName());
///Other data rendering codes.
} catch (Exception e) {
e.printStackTrace();
}
return super.getView(position,convertView,parent);
}
ขอให้สังเกตว่าวิธีการ GetView ของ BoysAdapter ส่งกลับการเรียกไปยังgetView
วิธีการของ EndlessAdapter superclass นี่เป็นสิ่งที่จำเป็น 100%
ตอนนี้เพื่อสร้างอะแดปเตอร์ทำ:
adapter = new ModelAdapter() {
@Override
public void onScrollToBottom(int bottomIndex, boolean moreItemsCouldBeAvailable) {
if (moreItemsCouldBeAvailable) {
makeYourServerCallForMoreItems();
} else {
if (loadMore.getVisibility() != View.VISIBLE) {
loadMore.setVisibility(View.VISIBLE);
}
}
}
@Override
public void onScrollAwayFromBottom(int currentIndex) {
loadMore.setVisibility(View.GONE);
}
@Override
public void onFinishedLoading(boolean moreItemsReceived) {
if (!moreItemsReceived) {
loadMore.setVisibility(View.VISIBLE);
}
}
};
loadMore
รายการเป็นปุ่มหรือองค์ประกอบ UI อื่น ๆ ที่อาจต้องคลิกเพื่อดึงข้อมูลเพิ่มเติมจาก URL เมื่อวางไว้ตามที่อธิบายไว้ในรหัสอะแดปเตอร์รู้ว่าเมื่อใดที่จะแสดงปุ่มนั้นและเมื่อต้องการปิดใช้งาน เพียงแค่สร้างปุ่มใน xml ของคุณและวางไว้ตามที่แสดงในรหัสอะแดปเตอร์ด้านบน
สนุก.