写在之前:
一年前当我第一次遇到了要上拉加载的时候,当时还是有一些信心的,但是很快我的信心被摧毁了,当时我做出的上拉加载一塌糊涂,完全啊没法看,实在是心塞的不行。之后又想到了使用网络上的框架,当时搜索了很多,有一个叫做廖枯秋的人写的框架,但是下载下来之后实在是看不进去,而且他的也没有写明白到底怎么去使用(当然,估计更多的原因是因为我实在是看不进去别人的程序),之后我就一个在用我写的一个,当时的我不知道进程池,不知道Asycntask,好吧虽然到现在还是不会写这个单词,单词是异步任务的意思,当然就是和主界面分开的意思。。其实每个人自己也可以利用handle写出一个Asynctask一样的东西,当然我自己到现在在实际中也没有体会到区别是什么,如果说有区别,那就是Asycntask更加方便使用,估计如果看了源码我就懂了。但是最近真的好心塞啊。找不到实习,上了大学之后,自以为自己很清高,,,实则穷秀才,听到别人都是内推的消息,简直是心塞啊,心塞之下,写了这篇
关于上拉加载 (一个是可以自己定制底部的东西的,一个是不能自己定制底部的,,,,我自己做的很丑)
首先:这是我自己写的底部加载页面
文件名字是:listview_footer.xml
很好理解,什么都没有,只有一个progressbar(转圈圈)一个textview(写现在是什么状态)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="40dp"
android:background="#dadada"
android:gravity="center">
<ProgressBar
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_marginRight="5dp"
android:id="@+id/pro"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="40dp"
android:textSize="13sp"
android:textStyle="bold"
android:textColor="#9c9c9c"
android:gravity="center"
android:id="@+id/footer_text"
android:text="正在刷新..."/>
</LinearLayout>
</LinearLayout>
这是我的不能定制底部的, 可以下载了直接使用,当然记得改一次前面的部分,这个类使用了前面的
脚部布局,可以直接复制了使用,在下面我会粘贴上我自己使用的代码
package com.chunni.android.chunni.tool;
import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.chunni.android.chunni.R;
import java.util.concurrent.ExecutorService;
/**
* Created by 蒲公英 on 2017/5/31.
*/
public class ListViewUpload2 extends ListView {
//开始加载的标识符号
private final int LOAD = 100002;
//如果加载失败,比如你去网上获取内容了,失败了
private final int FAIL = 100007;
//一步加载几个
private int STEP = 0;
//附带自己线程池的初始化,就是你自己定义了线程池,让Ascnytask在你的里面运行
/**
* 附带自己线程池的初始化,就是你自己定义了线程池,让Ascnytask在你的里面运行
* @param doload 接口(因为要根据这里的进度去操作另外的页面)
* @param STEP 一步加载的数量
* @param executors 你自己定义的线程池
*/
public void initInPool(Doload doload, int STEP, ExecutorService executors) {
this.doload = doload;
this.STEP = STEP;
this.executors = executors;
addFooter();
set_foot(1);
new MyAsyncTask().executeOnExecutor(this.executors);
}
//没有自己线程池的初始化
/**
* 初始化
* @param doload 接口
* @param STEP 一步的数量
*/
public void init(Doload doload, int STEP) {
this.doload = doload;
this.STEP = STEP;
addFooter();
set_foot(1);
new MyAsyncTask().execute();
}
//线程池
private ExecutorService executors = null;
//如果(数据加载失败)时候你的load应该返回这个值
public static final int BADDATA = -1;
//下面的转圈圈
private ProgressBar pro = null;
//标记是不是还能进行加载
private boolean CAN = false;
//起点
private float start = 0;
//最大高度 测量得到
private int highest = 0;
//大小设置工具
private LayoutParams layoutParams = null;
//底部布局
private LinearLayout footer = null;
//底部文字
private TextView text_footer = null;
public ListViewUpload2(Context context) {
super(context);
}
public ListViewUpload2(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewUpload2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* load :加载的时候执行的内容,返回值是这一次加载的数量,如果网络请求失败,没有加载到,返回BADDATA(-1)
* finish:加载完成时候的操作,就是这里加载完了,那边要执行的操作
*/
public interface Doload{
int load();
void finish();
}
//实例化接口
private Doload doload;
/**
* 主要的代码:说一下想法,如果CAN为true,那么就去并且已经滑动到最后了,那么按下才有加载
* 这个时候就已经确定了start也就是你开始的地方
* 然后开始滑动了,你移动的时候,根据你上拉的程度,不断地刷新底部view的高度,
* 之后手指松开的时候,如果松开的位置-开始的位置 大于 底部的高度,可以加载,然后去执行Asynctask
* @param ev
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
if (this.getLastVisiblePosition() == this.getCount() - 1 && CAN)
{
start = ev.getY();
}
break;
case MotionEvent.ACTION_MOVE:
if (start > 0)
{
float move = ev.getY() - start;
if (move < 0 && move > -highest){
set_foot((int) -move);
text_footer.setText("上拉加载");
}
if (move < -highest) {
set_foot(highest);
text_footer.setText("松开加载");
}
}
break;
case MotionEvent.ACTION_UP:
if (start > 0) {
if ((ev.getY() - start) < -highest) {
if (this.executors == null){
new MyAsyncTask().execute();
}else{
new MyAsyncTask().executeOnExecutor(this.executors);
}
}
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 设置底部高度为1,解决了好多设置不可见引起的问题。。
* @param height
*/
private void set_foot(int height){
layoutParams.height = height;
footer.setLayoutParams(layoutParams);
Log.i("xjxu" , height + " " + footer.getHeight());
}
/**
* 自定义的异步任务
*/
private class MyAsyncTask extends AsyncTask<Void, Integer, Integer> {
@Override
protected Integer doInBackground(Void... objects) {
publishProgress(LOAD);
int sign = doload.load();
if (sign == -1){
publishProgress(FAIL);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return sign;
}
@Override
protected void onProgressUpdate(Integer... pros) {
super.onProgressUpdate(pros);
switch (pros[0]){
case LOAD:
CAN = false;
start = 0;
set_foot(highest);
text_footer.setText("加载中");
break;
case FAIL:
set_foot(highest);
pro.setVisibility(GONE);
text_footer.setText("请检查你的网络连接");
break;
}
}
@Override
protected void onPostExecute(Integer count) {
super.onPostExecute(count);
if (count == STEP || count == BADDATA){
pro.setVisibility(VISIBLE);
CAN = true;
set_foot(1);
return;
}
else{
CAN = false;
set_foot(highest);
text_footer.setText("已经没有更多内容了");
pro.setVisibility(GONE);
}
doload.finish();
}
}
/**
* 添加底部
*/
private void addFooter(){
footer = (LinearLayout) LayoutInflater.from(this.getContext()).inflate(R.layout.listview_footer, null);
//最后一次参数的意思是 是不是可以选择到,如果是true,点了会触发onitemclick
this.addFooterView(footer, null, false);
this.setFooterDividersEnabled(false);
text_footer = footer.findViewById(R.id.footer_text);
pro = footer.findViewById(R.id.pro);
//测量
footer.measure(0 , 0);
highest = footer.getMeasuredHeight();
//初始化param
layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
set_foot(1);
}
}
我自己使用的实际例子
这是布局,注意如果你直接复制了我的布局和类 注意更改包名哦
<com.chunni.android.chunni.tool.ListViewUpload2
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:visibility="gone"
android:divider="@null"
android:id="@+id/lst">
</com.chunni.android.chunni.tool.ListViewUpload2>
这是我使用的代码/**
* 初始化上拉加载控件
*/
private void initUpload(){
listViewUpload.setAdapter(uploadAdapter = new UploadAdapter());
listViewUpload.init(new ListViewUpload2.Doload() {
@Override
public int load() {
String result = new NetWorkOut().outPost(App.SERVER + "article/artList?" +
"userId=" + App.USERPHONE +
"&start=" + uploads.size() +
"&end=" + (uploads.size() + 5));
if (result == null)
return -1;
JsonArray jsonArray = jsonParser.parse(result)
.getAsJsonObject()
.get("data_upload")
.getAsJsonArray();
if (uploads == null)
uploads = new JsonArray();
uploads.addAll(jsonArray);
return jsonArray.size();
}
@Override
public void finish() {
uploadAdapter.notifyDataSetChanged();
}
}, 5);
load();
}
写在最后,一直以为自己写的很短,但是贴出来还是发现很长,所以我可能会之后上传一个github的连接,当然现在的我一个github也没有发过,。。。。最后的最后,如果有什么问题或者建议请写在下面好吗,亲们^_^
也希望能给像当初的我一样的人一点帮助,当然如果大神看到了,还请多多指教。。。
最后祝福自己。。。