您的位置:首页 > 其它

ListView的私人订制

2016-08-30 14:38 134 查看
转载请注明出处:http://blog.csdn.net/magic_jss/article/details/52369091

现在开发中Android RecyclerView可能用的比较多,不过ListView作为常用控件学习它的使用和扩展也是十分重要的。简单封装了一个下拉刷新和上拉加载的ListView,你是否也想有个私人订制的ListView呢?或许这篇文章能够帮到你,如有问题恳请指正!欢迎评论哦!

效果图:



由于电脑和模拟器的原因可能不太清晰及略卡顿,真机上则很清晰及流畅。

1、自定义ListView

直接上代码

/**
* Created by magic on 2016年5月12日.带下拉刷新/上拉加载的listview
*/
public class PullDownRefurbishLoadListView extends ListView implements
OnScrollListener, OnClickListener {

/**
* head view
*/
private View headView;
/**
* head view height
*/
private int headViewHeight;
/**
* 是否可以下滑刷新
*/
private boolean isPullDownRefurbish = false;
/**
* 文本状态描述
*/
private TextView tev_status;
/**
* 进度条
*/
private ImageView progressBar;
/**
* foot view
*/
private View footView;
/**
* foot view height
*/
private int footViewHeight;
/**
* 是否可以上拉加载
*/
private boolean isPullHighLoad = false;
/**
* 底部布局
*/
LinearLayout layout_listviewFoot;
/**
* 底部文本状态描述
*/
private TextView tev_status_foot;
/**
* 进度条
*/
ImageView progressBar_foot;
/**
* 按下后的初始Y位置
*/
private float beginY = 0;
/**
* 移动的距离
*/
private int moveY = 0;
/**
* 正常状态
*/
private final static int NONE = 0;
/**
* 下拉/上拉状态
*/
private final static int PULL = 1;
/**
* 释放刷新状态
*/
private final static int RELEASE = 2;
/**
* 刷新状态
*/
private final static int REFURBISH = 3;
/**
* 状态
*/
private static int STATUS;
/**
* 是否允许下拉刷新
*/
private boolean isRefurbishAble = true;
/**
* 是否允许上拉加载
*/
private boolean isLoadAble = true;
/**
* context
*/
private Context context;
/**
* 动画
*/
private RotateAnimation rotateAnimation, rotateAnimation2;
/**
* 接口
*/
private IPullDownRefurbishLoadListView refurbishLoadListView;

public PullDownRefurbishLoadListView(Context context) {
super(context);
init(context);
}

public PullDownRefurbishLoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

public PullDownRefurbishLoadListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context);
}

/**
* 添加head/foot布局
*
* @param context
*/
private void init(Context context) {
headView = LayoutInflater.from(context).inflate(R.layout.listview_head,
null);
this.addHeaderView(headView);
// 设置滑动监听
this.setOnScrollListener(this);
headView.measure(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
headViewHeight = headView.getMeasuredHeight();
// 设置headView 偏移出屏幕
headView.setPadding(0, -headViewHeight, 0, 0);

tev_status = (TextView) findViewById(R.id.tev_listviewHead_status);
progressBar = (ImageView) findViewById(R.id.prb_listviewHead_refurbish);

footView = LayoutInflater.from(context).inflate(
R.layout.listview_footer, null);
this.addFooterView(footView);
footView.measure(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
footViewHeight = footView.getMeasuredHeight();

layout_listviewFoot = (LinearLayout) footView
.findViewById(R.id.layout_listviewFoot);
tev_status_foot = (TextView) footView
.findViewById(R.id.tev_listviewFoot_state);
progressBar_foot = (ImageView) findViewById(R.id.prb_listviewFoot_load);
tev_status_foot.setOnClickListener(this);
this.context = context;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:

beginY = ev.getY();

if (STATUS == REFURBISH) {
// 不消耗事件
return false;
}

case MotionEvent.ACTION_MOVE:

this.moveY = (int) (ev.getY() - beginY);

if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) {
if (moveY > 0) {
if (moveY > headViewHeight) {
STATUS = RELEASE;
if (moveY >= (headViewHeight + dp2px(20, context))) {
moveY = headViewHeight + dp2px(20, context);
}
} else if (moveY > 0 && moveY <= headViewHeight) {
STATUS = PULL;
} else {
STATUS = NONE;
}
setRefurbishByStatus((int) moveY);
}
}

if (isLoadAble && isPullHighLoad && moveY < 0) {
tev_status_foot.setVisibility(View.GONE);
progressBar_foot.setVisibility(View.VISIBLE);
if (Math.abs(moveY) > footViewHeight) {
STATUS = RELEASE;
} else if (Math.abs(moveY) > 0
&& Math.abs(moveY) <= footViewHeight) {
STATUS = PULL;
} else {
STATUS = NONE;
}
}

break;

case MotionEvent.ACTION_UP:
if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) {
switch (STATUS) {
case PULL:
moveY = 0;
setRefurbishByStatus(-headViewHeight);
break;
case RELEASE:
STATUS = REFURBISH;
setRefurbishByStatus((int) moveY);
if (refurbishLoadListView != null) {
refurbishLoadListView.refurbish();
}
break;

}
}

if (isLoadAble && isPullHighLoad && moveY < 0) {
switch (STATUS) {
case PULL:
moveY = 0;
STATUS = NONE;
tev_status_foot.setVisibility(View.VISIBLE);
progressBar_foot.setVisibility(View.GONE);
break;
case RELEASE:
STATUS = REFURBISH;
progressBar_foot.clearAnimation();
if (rotateAnimation2 != null) {
rotateAnimation2.cancel();
}
setAnimationToProgressBarFoot();
break;
}
}
break;
}
return super.onTouchEvent(ev);
}

/**
* 设置head布局的上内边距
*
* @param size
*/
private void setHeadPaddingTop(int size) {
size = size + (-headViewHeight);
headView.setPadding(0, size, 0, 0);
}

/**
* 根据状态设置刷新HeadView显示的内容
*/
private void setRefurbishByStatus(int moveY) {
switch (STATUS) {
case NONE:
tev_status.setText("下拉刷新");
progressBar.setImageResource(R.drawable.ic_ptr_pull);
setHeadPaddingTop(-headViewHeight);
break;
case PULL:
tev_status.setText("下拉刷新");
progressBar.setImageResource(R.drawable.ic_ptr_pull);
setHeadPaddingTop(moveY);
break;
case RELEASE:
tev_status.setText("释放刷新");
progressBar.setImageResource(R.drawable.ic_ptr_release);
setHeadPaddingTop(moveY);
break;
case REFURBISH:
tev_status.setText("刷新中");
progressBar.setImageResource(R.drawable.ic_ptr_loading);
setHeadPaddingTop(headViewHeight);

if (rotateAnimation == null) {
rotateAnimation = new RotateAnimation(0.0f, 180.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(150);
rotateAnimation.setRepeatCount(-1);
}
progressBar.setAnimation(rotateAnimation);
rotateAnimation.start();
break;
}
}

/**
* 设置对外公开接口
*
* @param pullDownRefurbish
*/
public void setIPullDownRefurbish(
IPullDownRefurbishLoadListView refurbishLoadListView) {
this.refurbishLoadListView = refurbishLoadListView;
}

/**
* 刷新完成执行
*/
public void setPullDownRefurbishFinish() {
moveY = 0;
STATUS = NONE;
setRefurbishByStatus((int) moveY);
progressBar.clearAnimation();
rotateAnimation.cancel();
}

/**
* 加载完成执行
*/
public void setPullDownLoadFinish() {
moveY = 0;
STATUS = NONE;
progressBar_foot.clearAnimation();
rotateAnimation2.cancel();
progressBar_foot.setVisibility(View.GONE);
tev_status_foot.setVisibility(View.VISIBLE);
}

/**
* 设置是否允许下拉刷新
*
* @param isRefurbishAble
*/
public void setRefurbishAble(boolean isRefurbishAble) {
this.isRefurbishAble = isRefurbishAble;
}

/**
* 设置是否可以上拉加载
*
* @param isLoadAble
*/
public void setLoadAble(boolean isLoadAble) {
this.isLoadAble = isLoadAble;
if (!isLoadAble) {
layout_listviewFoot.setVisibility(View.GONE);
}
}

@Override
public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
// 参数:
// 查看其滚动状态的视图
// firstvisibleitem -第一个可见的细胞指数(忽略如果visibleitemcount = = 0)
// visibleitemcount -可见细胞数
// totalitemcount -在列表适配器项目数

// arg1为0时 列表在最顶部
isPullDownRefurbish = arg1 == 0 ? true : false;
// arg1为最后一个时arg1==arg3
isPullHighLoad = (arg1 + arg2) == arg3 ? true : false;
}

@Override
public void onScrollStateChanged(AbsListView arg0, int arg1) {
}

/**
* dp转px
*/
private int dp2px(float value, Context context) {
final float scale = context.getResources().getDisplayMetrics().densityDpi;
return (int) (value * (scale / 160) + 0.5f);
}

/**
* 为progressBar_foot设置动画
*/
private void setAnimationToProgressBarFoot() {
if (rotateAnimation2 == null) {
rotateAnimation2 = new RotateAnimation(0.0f, 180.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation2.setDuration(150);
rotateAnimation2.setRepeatCount(-1);
}
progressBar_foot.setAnimation(rotateAnimation2);
rotateAnimation2.start();
if (refurbishLoadListView != null) {
refurbishLoadListView.load();
}
}

@Override
public void onClick(View v) {
// 点击查看更多
tev_status_foot.setVisibility(View.GONE);
progressBar_foot.setVisibility(View.VISIBLE);
setAnimationToProgressBarFoot();
}

/**
* 接口
*/
interface IPullDownRefurbishLoadListView {
/**
* 刷新事件回调
*/
void refurbish();

/**
* 加载回调
*/
void load();
}

}


以上代码主要步骤:

初始化的时候添加HeadView、FootView。

继承ListView实现OnScrollListener接口,重写onScroll方法,因为onScroll方法在ListView滑动的时候会一直回调,因此在onScroll方法中判断是否处于ListView的顶部/底部,从而处理下拉刷新/上拉加载的展现时机。

重写onTouchEvent方法,在按下、滑动、抬起的时候动态处理HeadView、FootView的展现。

添加回调接口,设置回调方法。

注释比较清楚,不在赘述。

2、xml文件

主布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<com.magic.test_listviewrefurbish.PullDownRefurbishLoadListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</LinearLayout>


layout/listview_head.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="20dp"
android:paddingTop="20dp" >

<ImageView
android:id="@+id/prb_listviewHead_refurbish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_ptr_pull" />

<TextView
android:id="@+id/tev_listviewHead_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="下拉刷新"
android:textColor="#afafaf"
android:textSize="12sp" />
</LinearLayout>

</LinearLayout>


listview_footer.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical" >

<LinearLayout
android:id="@+id/layout_listviewFoot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="15dp"
android:paddingTop="15dp" >

<TextView
android:id="@+id/tev_listviewFoot_state"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="查看更多"
android:textColor="@android:color/darker_gray" />

<ImageView
android:id="@+id/prb_listviewFoot_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_ptr_loading"
android:visibility="gone" />
</LinearLayout>

</LinearLayout>


3、Activity中使用

/**
* Created by magic on 2016年5月12日.带下拉刷新/上拉加载的listview
*/
public class MainActivity extends Activity implements OnItemClickListener {

PullDownRefurbishLoadListView listView;
MyAdapter adapter;
List<String> list = new ArrayList<String>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
}

private void initView() {
listView = (PullDownRefurbishLoadListView) findViewById(R.id.listview);
list.add("a");
adapter = new MyAdapter(this, list);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
//设置是否可以下拉刷新,默认为true
listView.setRefurbishAble(true);
//设置是否可以上拉加载,默认为true
listView.setLoadAble(true);

listView.setIPullDownRefurbish(new IPullDownRefurbishLoadListView() {

@Override
public void refurbish() {
new Handler().postDelayed(new Runnable() {

@Override
public void run() {
list.add(0, "c");
adapter.notifyDataSetChanged();
listView.setPullDownRefurbishFinish();
}
}, 2000);
}

@Override
public void load() {
new Handler().postDelayed(new Runnable() {

@Override
public void run() {
list.add("b");
adapter.notifyDataSetChanged();
listView.setPullDownLoadFinish();
}
}, 2000);
}
});
}

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Toast.makeText(this, "Hello  " + arg2, Toast.LENGTH_SHORT).show();
}
}


Adapter比较简单就不写了!

整个项目下载地址:http://download.csdn.net/detail/magic_jss/9616947

END!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐