剛開始學習的Listview,後面想做一個上拉重新整理以及下拉加載,但是發現挺麻煩的,在github上面看見人家推薦使用RecycleView,在網上看看确實挺容易的,一般都是推薦RecycleView+google 提供的SwipeRefreshLayout,有一點不知道google怎麼搞的,(SwipeRefreshLayout居然和RecyclerView沖突,連續下拉,重新整理樣式會一團糟,還會卡住)—這個是我看别人說的。現在很多人都知道RecycleView的作用了,是以他的東西我也不多說了,我就說下SwipeToLoadLayout,反正我在網上看這類資料都有點亂,我就自己寫一篇,以後忘了再看看!
1.支援上拉下拉,頭部和尾部也都是用接口實作,是以我們隻需要在實作接口裡面的内容就可以輕松寫一個重新整理效果,就像使用BaseAdapter一樣,自己慢慢弄,都可以輕松實作。
2.隻需要将SwipeToLoadLayout包裹住内容,支援各種View和ViewGroup(RecycleView、TextView…….++) 就可以實作啦
3.代碼簡單,層次分明。适合新手(反正我覺得挺好的,新手一枚,有什麼錯誤的地方别見笑)。
文章實作SwipeToLoadLayout+RecyleView,并且自定義上拉重新整理以及下拉加載,現在很多清單都需要有網絡圖檔,我就一并寫在這個了吧,實作自定義Item的點選事件,以及擷取Item裡的内容。
因為内容資料本地添加太麻煩,我就用了Bmob的後端雲資料庫來使用(太懶=-=)。
這裡推薦一個圖檔控件Fresco ,隻需要給他圖檔位址就可以了。
1.顯示占位圖直到加載完成;
2.下載下傳圖檔;
3.緩存圖檔;
4.圖檔不再顯示時,從記憶體中移除;
解決大問題,不然用異步下載下傳還要寫緩存,麻煩!
實際效果如圖所示:
好啦好啦,開始吧=-=
第一步
repositories {
maven { url “https://jitpack.io” }
}
compile ‘com.android.support:recyclerview-v7:24.2.1’
compile ‘com.github.Aspsine:SwipeToLoadLayout:1.0.3’
compile ‘com.facebook.fresco:fresco:0.12.0’
這個用android studio的應該都會吧,不會我也無奈了=-=
首頁面布局檔案
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.aspsine.swipetoloadlayout.SwipeToLoadLayout
android:id="@+id/swipeToLoadLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.plix.recyleswipetoloadlayout.RefreshHeadView
android:id="@+id/swipe_refresh_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/swipe_target"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical">
</android.support.v7.widget.RecyclerView>
<com.example.plix.recyleswipetoloadlayout.LoadMoreView
android:id="@+id/swipe_load_more_footer"
android:layout_width="match_parent"
android:padding="20dp"
android:gravity="center"
android:layout_height="wrap_content" />
</com.aspsine.swipetoloadlayout.SwipeToLoadLayout>
</RelativeLayout>
下面是首頁面代碼
public class SwipeToLayoutActivity extends Activity implements OnRefreshListener, OnLoadMoreListener {
private RecyclerView mRecycleView;
SwipeToLoadLayout swipeToLoadLayout;
private RecyleViewApadter adapter;
private int size=10;
private List<person> data;
private LinearLayoutManager layoutManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recyle_main);
Fresco.initialize(this);//fresco的控件初始化
Bmob.initialize(this,"這個不能看,哈哈~-~");
//RecycleView的一些東西,不知道的去看看RecycleView
swipeToLoadLayout = ((SwipeToLoadLayout) findViewById(R.id.swipeToLoadLayout));
mRecycleView = ((RecyclerView) findViewById(R.id.swipe_target));
layoutManager = new LinearLayoutManager(this);//建立線性布局
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);//垂直方向
mRecycleView.addItemDecoration(new DividerItemDecoration(getApplicationContext(), DividerItemDecoration.VERTICAL_LIST));//添加分割線
mRecycleView.setLayoutManager(layoutManager);//給RecyclerView設定布局管理器
mRecycleView.setItemAnimator(new DefaultItemAnimator());//設定Item增加、移除動畫
find(size);
swipeToLoadLayout.setOnRefreshListener(this);//下拉
swipeToLoadLayout.setOnLoadMoreListener(this);//上拉
//RecycleView的點選事件
mRecycleView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
person per= data.get(position);
String aaa= per.getName();//獲得點選的item的裡面的值
Toast.makeText(SwipeToLayoutActivity.this,aaa,Toast.LENGTH_SHORT).show();
}
@Override
public void onLongClick(View view, int posotion) {
}
}));
}
private void Data(List<person> data)
{
adapter = new RecyleViewApadter(this,data);//傳遞資料搭載擴充卡
mRecycleView.setAdapter(adapter);
}
//資料源自己想用什麼就自己寫
private void find(int size){//這個是查找資料,别看
data = new ArrayList<>();
BmobQuery<person> query = new BmobQuery<person>();
query.addWhereEqualTo("address","桂林");
query.order("-createdAt");
query.setLimit(size);
query.findObjects(this, new FindListener<person>() {
@Override
public void onSuccess(List<person> lists) {
for (person p : lists) {
data.add(p);
}
Data(data);
System.out.println("6666");
}
@Override
public void onError(int i, String s) {
System.out.println("55555"+i+s);
}
});
}
//上拉加載的時候這個方法會執行,在這裡面寫上拉時的資料加載
@Override
public void onLoadMore() {
swipeToLoadLayout.postDelayed(new Runnable() {
@Override
public void run() {
size=size+;
find(size);
adapter.notifyDataSetChanged();
swipeToLoadLayout.setLoadingMore(false);
}
},);
}
//下拉重新整理的時候這個方法會執行,重新搭載一下資料,重新整理一下就好了
@Override
public void onRefresh() {
swipeToLoadLayout.postDelayed(new Runnable() {
@Override
public void run() {
find(size);
adapter.notifyDataSetChanged();
swipeToLoadLayout.setRefreshing(false);
}
},);
}
//這個RecycleView的擴充卡,簡單說一下
public class RecyleViewApadter extends RecyclerView.Adapter<HomeViewHolder> {
private Context context;
private List<person> per;
public RecyleViewApadter(Context context,List<person> per) {
this.context= context;
this.per=per;
}
//在這裡自定義item 找出控件
@Override
public SwipeToLayoutActivity.HomeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyleview_item, parent, false);
HomeViewHolder homeViewHolder= new HomeViewHolder(view);
homeViewHolder.address = ((TextView) view.findViewById(R.id.hotel_jiudian_address));
homeViewHolder.name = ((TextView) view.findViewById(R.id.hotel_jiudian_name));
homeViewHolder.type = ((TextView) view.findViewById(R.id.hotel_jiudian_type));
homeViewHolder.price = ((TextView) view.findViewById(R.id.hotel_jiudian_price));
homeViewHolder.image = ((SimpleDraweeView) view.findViewById(R.id.hotel_jiudian_image));
return homeViewHolder;
}
// 資料的綁定顯示
@Override
public void onBindViewHolder(SwipeToLayoutActivity.HomeViewHolder holder, int position) {
HomeViewHolder home= (HomeViewHolder)holder;
home.getName().setText(per.get(position).getName());
home.getAddress().setText(per.get(position).getAddress());
home.getPrice().setText(per.get(position).getPrice());
home.getType().setText(per.get(position).getType());
home.getImage().setImageURI(per.get(position).getImgurl());//給fresco網絡圖檔位址就會自動顯示
}
@Override
public int getItemCount() {
return per.size();
}
}
//自定義的ViewHolder,持有每個Item的的所有界面元素
public class HomeViewHolder extends RecyclerView.ViewHolder {
public TextView address;
public TextView type;
public TextView name;
public TextView price;
public SimpleDraweeView image;//這個是fresco的圖檔控件
public TextView getAddress() {
return address;
}
public TextView getType() {
return type;
}
public TextView getName() {
return name;
}
public TextView getPrice() {
return price;
}
public SimpleDraweeView getImage() {
return image;
}
public HomeViewHolder(View itemView) {
super(itemView);
}
}
//這個是item的點選事件,我在其他文章上面看到的,覺得這個最好,就搬了過來
public static class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private View childView;
private RecyclerView touchView;
public RecyclerItemClickListener(Context context, final OnItemClickListener mListener) {
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onSingleTapUp(MotionEvent ev) {
if (childView != null && mListener != null) {
mListener.onItemClick(childView, touchView.getChildPosition(childView));
}
return true;
}
@Override
public void onLongPress(MotionEvent ev) {
if (childView != null && mListener != null) {
mListener.onLongClick(childView, touchView.getChildPosition(childView));
}
}
});
}
GestureDetector mGestureDetector;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
public void onLongClick(View view, int posotion);
}
@Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
mGestureDetector.onTouchEvent(motionEvent);
childView = recyclerView.findChildViewUnder(motionEvent.getX(), motionEvent.getY());
touchView = recyclerView;
return false;
}
@Override
public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}//點選事件到這裡
}
頭部下拉重新整理頁面
//我這裡繼承RelativeLayout,想繼承什麼都可以,TextView也可以
public class RefreshHeadView extends RelativeLayout implements SwipeRefreshTrigger,SwipeTrigger {
TextView mDescText;
TextView test;
ImageView imageView;
private ObjectAnimator anim;//動畫
private boolean isRelease;
public RefreshHeadView(Context context) {
this(context, null, );
}
public RefreshHeadView(Context context, AttributeSet attrs) {
this(context, attrs, );
}
public RefreshHeadView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mDescText = new TextView(getContext());
test= new TextView(getContext());
mDescText.setTextSize();
mDescText.setTextColor(Color.GRAY);
mDescText.setText("下拉重新整理");
//添加線性的父布局 這個不懂的話 搜尋一下線性和相對布局
LinearLayout ll = new LinearLayout(getContext());
RelativeLayout.LayoutParams llParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
llParams.addRule(CENTER_IN_PARENT);
ll.setLayoutParams(llParams);
ll.setPadding(,,,);
imageView= new ImageView(getContext());
imageView.setImageResource(R.drawable.qianjin);
ll.addView(imageView);
ll.addView(mDescText);
addView(ll);
}
//下拉到一定位置之後調用此方法
@Override
public void onRefresh() {
//開始重新整理,啟動動畫
anim = ObjectAnimator.ofFloat(imageView, "rotation", imageView.getRotation(), imageView.getRotation()+f)
.setDuration();
anim.setRepeatCount(ValueAnimator.INFINITE);
anim.setRepeatMode(ValueAnimator.RESTART);
anim.start();
mDescText.setText("正在加載資料");
}
//下拉之前調用此方法
@Override
public void onPrepare() {
imageView.setImageResource(R.drawable.qianjin);
isRelease = false;
}
// 當下拉到一定位置之後 顯示重新整理
@Override
public void onMove(int yScroll, boolean isComplete, boolean b1) {
if (!isComplete) {
if (yScroll < getHeight()) {//Y軸與下拉控件
mDescText.setText("下拉重新整理");
} else {
mDescText.setText("松開重新整理更多");
}
}
}
// 上拉到一定距離之後松開重新整理
@Override
public void onRelease() {
isRelease = true;
}
//重新整理完成後
@Override
public void onComplete() {
anim.cancel();
imageView.setImageResource(R.drawable.jindu);
mDescText.setText("加載完成");
}
//重置
@Override
public void onReset() {
}
}
底部上拉加載代碼(大同小異)
public class LoadMoreView extends RelativeLayout implements SwipeLoadMoreTrigger,SwipeTrigger {
private ImageView shangla;
private TextView textView;
private ObjectAnimator anim;
private boolean isRelease;
public LoadMoreView(Context context) {
super(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public LoadMoreView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public LoadMoreView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public LoadMoreView(Context context, AttributeSet attrs) {
super(context, attrs);
initview();
}
private void initview(){
shangla= new ImageView(getContext());
textView= new TextView(getContext());
//添加線性的父布局
LinearLayout ll = new LinearLayout(getContext());
RelativeLayout.LayoutParams llParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
llParams.addRule(CENTER_IN_PARENT);
ll.setLayoutParams(llParams);
ll.setPadding(,,,);
shangla.setImageResource(R.drawable.shangla);
ll.addView(shangla);
ll.addView(textView);
addView(ll);
}
@Override
public void onLoadMore() {
//上啦到一定位置之後調用此方法
shangla.setImageResource(R.drawable.qianjin);
anim = ObjectAnimator.ofFloat(shangla, "rotation", shangla.getRotation(), shangla.getRotation()+f)
.setDuration();
anim.setRepeatCount(ValueAnimator.INFINITE);
anim.setRepeatMode(ValueAnimator.RESTART);
anim.start();
textView.setText("正在加載");
}
@Override
public void onPrepare() {
//上拉之前調用此方法
shangla.setImageResource(R.drawable.shangla);
isRelease = false;
}
@Override
public void onMove(int yScroll, boolean isComplete, boolean b1) {
// 當上拉到一定位置之後 顯示重新整理
if (!isComplete){
if (yScroll<getHeight())
{
shangla.setImageResource(R.drawable.shangla);
textView.setText("上拉加載");
}else {
shangla.setImageResource(R.drawable.qianjin);
textView.setText("松開加載更多");
}
}
}
@Override
public void onRelease() {
//上拉到一定距離之後松開重新整理
isRelease = true;
}
@Override
public void onComplete() {
anim.cancel();
shangla.setImageResource(R.drawable.jindu);
textView.setText("加載完成");
}
@Override
public void onReset() {
//重置
}
}
最後說一下其他的
<item name="swipe_target" type="id" />
重新整理目标
<item name="swipe_refresh_header" type="id" />
重新整理頭部
<item name="swipe_load_more_footer" type="id" />
重新整理尾部
注意,swipetoloadlayout中布局包裹的View id是指定的,不能亂改,否則找不到 (這個我也沒試過,我直接就用了,反正我的沒出錯)
新手寫部落格記錄學習生涯,有時候難免有出錯的地方,大家有什麼可以幫助的,還望不吝賜教!!!謝謝
最後附上參考的資料連結:
RecyclerView使用詳解
SwipeToLoadLayout–小白也能輕松定制自己的重新整理效果
Fresco開始使用
Android RecyclerView的點選事件