listview上下拉组件[自己重写的]

在网上找了好多这类组件总是用得不太顺手,数据一加载多了就卡得不行,现在自己做了一个,代码基本上是最优化的,方便大家使用

先看看效果吧:
[img]http://dl2.iteye.com/upload/attachment/0087/9123/26fef5ac-6294-3bd7-9fa6-01406d4ac50e.jpg[/img]
[img]http://dl2.iteye.com/upload/attachment/0087/9125/7515281b-f96f-39b0-aaa7-2822e99293af.jpg[/img]
[img]http://dl2.iteye.com/upload/attachment/0087/9127/5ab060e7-8039-3f7a-8680-7ee63b5a64a8.jpg[/img]

下面是所有代码:
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.iaiai.activity"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="8" />

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".ListviewTestActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>


main.xml

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

<com.iaiai.activity.DragListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</LinearLayout>


list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal" >

<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="15sp" />

</LinearLayout>


ListviewTestActivity.java

package com.iaiai.activity;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

/**
*
* <br/>
* Title: ListviewTestActivity.java<br/>
* E-Mail: 176291935@qq.com<br/>
* QQ: 176291935<br/>
* Http: iaiai.iteye.com<br/>
* Create time: 2013-8-6 下午4:50:30<br/>
* <br/>
* @author 丸子
* @version 0.0.1
*/
public class ListviewTestActivity extends Activity {

private DragListView listView;

private List<String> titles = new ArrayList<String>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

listView = (DragListView) findViewById(R.id.listView);

for(int i=0;i<30;i++){
titles.add("标题:"+i);
}

MyAdapter adapter = new MyAdapter();
listView.setAdapter(adapter);
listView.setHandler(new DragListView.Handler() {
@Override
public void upRefresh() {
// listView.closeHeader();
}
@Override
public void downRefresh() {
// listView.closeFooter();
}
});
}

public class MyAdapter extends BaseAdapter{

@Override
public int getCount() {
return titles.size();
}

@Override
public String getItem(int position) {
return titles.get(position);
}

@Override
public long getItemId(int position) {
return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(ListviewTestActivity.this).inflate(
R.layout.list_item, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.title);
textView.setText(titles.get(position));
return convertView;
}

}

}


DragListView.java

package com.iaiai.activity;

import java.text.SimpleDateFormat;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

/**
*
* <br/>
* Title: DragListView.java<br/>
* E-Mail: 176291935@qq.com<br/>
* QQ: 176291935<br/>
* Http: iaiai.iteye.com<br/>
* Create time: 2013-8-5 下午3:06:25<br/>
* <br/>
*
* @author 丸子
* @version 0.0.1
*/
public class DragListView extends ListView implements OnScrollListener, OnClickListener {

public interface Handler {
/**
* 手指从上往下拉刷新之后会调用此方法
*/
void upRefresh();

/**
* 手指从下往上拉刷新之后会调用此方法
*/
void downRefresh();
}

public DragListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

init(context);
}

public DragListView(Context context, AttributeSet attrs) {
super(context, attrs);

init(context);
}

public DragListView(Context context) {
super(context);

init(context);
}

/***
* 作用:测量 headView的宽和高.
*
* @param child
*/
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}

private void init(Context context) {
this.context = context;
headerLayout = getHeaderLayout();
addHeaderView(headerLayout, null, false);
mHeadViewHeight = headerLayout.getMeasuredHeight();
headerLayout.setPadding(0, -1 * mHeadViewHeight, 0, 0);

footerLayout = getFooterLayout();
addFooterView(footerLayout, null, false);

setOnScrollListener(this);// ListView滚动监听
}

private LinearLayout getHeaderLayout() {
LinearLayout headerLayout = new LinearLayout(context);
headerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 0));
headerLayout.setBackgroundResource(android.R.color.white);
headerLayout.setGravity(Gravity.CENTER);
headerLayout.setOrientation(LinearLayout.VERTICAL);

LinearLayout layout = new LinearLayout(context);
layout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setPadding(0, dipTopx(10), 0, 0);

headerProgressBar = new ProgressBar(context);
headerProgressBar.setLayoutParams(new LayoutParams(dipTopx(20), dipTopx(20)) );
headerProgressBar.setProgressDrawable(getResources().getDrawable(android.R.drawable.progress_horizontal));
headerProgressBar.setVisibility(View.GONE);
layout.addView(headerProgressBar);

headerTextView = new TextView(context);
headerTextView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
headerTextView.setText("下拉手指刷新");
layout.addView(headerTextView);
headerLayout.addView(layout);

headerTextView_date = new TextView(context);
headerTextView_date.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
headerTextView_date.setText(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));
headerTextView_date.setPadding(0, 0, 0, dipTopx(10));
headerLayout.addView(headerTextView_date);

measureView(headerLayout);
return headerLayout;
}

private LinearLayout getFooterLayout() {
LinearLayout footerLayout = new LinearLayout(context);
footerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 0));
footerLayout.setBackgroundResource(android.R.color.white);
footerLayout.setOrientation(LinearLayout.VERTICAL);

LinearLayout lineLayout = new LinearLayout(context);
lineLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dipTopx(1)));
lineLayout.setBackgroundColor(this.getCacheColorHint());
footerLayout.addView(lineLayout);

LinearLayout layout = new LinearLayout(context);
layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
layout.setPadding(0, dipTopx(10), 0, dipTopx(10));
layout.setGravity(Gravity.CENTER);
layout.setOrientation(LinearLayout.HORIZONTAL);

footerProgressBar = new ProgressBar(context);
footerProgressBar.setLayoutParams(new LayoutParams(dipTopx(20), dipTopx(20)));
footerProgressBar.setProgressDrawable(getResources().getDrawable(android.R.drawable.progress_horizontal));
footerProgressBar.setVisibility(View.GONE);
layout.addView(footerProgressBar);

footerTextView = new TextView(context);
footerTextView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
footerTextView.setText("加载更多");
layout.addView(footerTextView);
footerLayout.addView(layout);

measureView(footerLayout);
footerLayout.setOnClickListener(this);
return footerLayout;
}

// 拖拉ListView枚举所有状态
private enum DListViewState {
LV_NORMAL, // 普通状态
LV_PULL_REFRESH, // 下拉状态(为超过mHeadViewHeight)
LV_RELEASE_REFRESH, // 松开可刷新状态(超过mHeadViewHeight)
LV_LOADING, // 加载状态
LV_OVER; // 结束状态
}

public void setHandler(Handler handler) {
this.handler = handler;
}

private Context context;

private Handler handler;

private LinearLayout headerLayout;
private LinearLayout footerLayout;

private ProgressBar headerProgressBar,footerProgressBar;

private TextView headerTextView, headerTextView_date,footerTextView;

private boolean isScroller = true;// 是否屏蔽ListView滑动

private boolean mFirstItemIndex = false;// 当前视图能看到的第一个项的索引

private boolean mIsRecord = false;// 用于保证startY的值在一个完整的touch事件中只被记录一次

private int mStartY, mMoveY;// 按下是的y坐标,move时的y坐标

private DListViewState mlistViewState = DListViewState.LV_NORMAL;// 拖拉状态.(自定义枚举)
private DListViewState mfootViewState = DListViewState.LV_NORMAL;// 拖拉状态.(自定义枚举)

private final static int RATIO = 2;// 手势下拉距离比.

private int mHeadViewHeight;// headView的高(mHeadView)

@Override
public void onClick(View v) {
if(!getAdapter().isEmpty()){
if(mfootViewState==DListViewState.LV_NORMAL){
footerTextView.setText("正在刷新");
mfootViewState = DListViewState.LV_LOADING;
footerProgressBar.setVisibility(View.VISIBLE);
handler.downRefresh();
}
}
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

/**
* 关闭头
*/
public void closeHeader() {
mlistViewState = DListViewState.LV_NORMAL;
headerProgressBar.setVisibility(View.GONE);
headerLayout.setPadding(0, -1 * mHeadViewHeight, 0, 0);
setSelection(0);
}

/**
* 关闭底
*/
public void closeFooter() {
setSelection(getCount());
footerTextView.setText("加载更多");
footerProgressBar.setVisibility(View.GONE);
mfootViewState = DListViewState.LV_NORMAL;
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem <= 0) {
mFirstItemIndex = true;
} else {
mFirstItemIndex = false;
}
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
// 按下
case MotionEvent.ACTION_DOWN:
doActionDown(ev);
break;
// 移动
case MotionEvent.ACTION_MOVE:
doActionMove(ev);
break;
// 抬起
case MotionEvent.ACTION_UP:
doActionUp(ev);
break;
default:
break;
}

/***
* 如果是ListView本身的拉动,那么返回true,这样ListView不可以拖动.
* 如果不是ListView的拉动,那么调用父类方法,这样就可以上拉执行.
*/
if (isScroller) {
return super.onTouchEvent(ev);
} else {
return true;
}
}

/***
* 摁下操作
*
* 作用:获取摁下是的y坐标
*
* @param event
*/
void doActionDown(MotionEvent event) {
if(getAdapter().isEmpty()){
return;
}
mStartY = (int) event.getY();
if (mIsRecord == false && mFirstItemIndex) {
mIsRecord = true;
}
}

/***
* 拖拽移动操作
*
* @param event
*/
void doActionMove(MotionEvent event) {
if(getAdapter().isEmpty()){
return;
}
mMoveY = (int) event.getY();// 获取实时滑动y坐标
// 检测是否是一次touch事件.
if (mIsRecord == false && mFirstItemIndex) {
mStartY = (int) event.getY();
mIsRecord = true;
}
Log.i("********", "*****" + mIsRecord);

// 向下啦headview移动距离为y移动的一半.(比较友好)
int offset = (mMoveY - mStartY) / RATIO;

/***
* 如果touch关闭或者正处于Loading状态的话 return.
*/
if (mIsRecord == false || mlistViewState == DListViewState.LV_LOADING) {
return;
}

switch (mlistViewState) {
// 普通状态
case LV_NORMAL: {
Log.i("********", "******普通状态");
// 如果<0,则意味着上滑动.
if (offset > 0) {
// 设置headView的padding属性.
headerLayout.setPadding(0, offset - mHeadViewHeight, 0, 0);
mlistViewState = DListViewState.LV_PULL_REFRESH;// 下拉状态
}

}
break;
// 下拉状态
case LV_PULL_REFRESH: {
setSelection(0);// 时时保持在顶部.
headerTextView.setText("下拉手指刷新");
headerTextView_date.setText(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));
// 设置headView的padding属性.
headerLayout.setPadding(0, offset - mHeadViewHeight, 0, 0);
if (offset < 0) {
/***
* 要明白为什么isScroller = false;
*/
isScroller = false;
mlistViewState = DListViewState.LV_NORMAL;// 普通状态
} else if (offset > mHeadViewHeight) {// 如果下拉的offset超过headView的高度则要执行刷新.
mlistViewState = DListViewState.LV_RELEASE_REFRESH;// 更新为可刷新的下拉状态.
}
}
break;
// 可刷新状态
case LV_RELEASE_REFRESH: {
Log.i("********", "******可刷新状态");
setSelection(0);// 时时保持在顶部
headerTextView.setText("松开手指刷新");
// 设置headView的padding属性.
headerLayout.setPadding(0, offset - mHeadViewHeight, 0, 0);
// 下拉offset>0,但是没有超过headView的高度.那么要goback 原装.
if (offset >= 0 && offset <= mHeadViewHeight) {
mlistViewState = DListViewState.LV_PULL_REFRESH;
} else if (offset < 0) {
mlistViewState = DListViewState.LV_NORMAL;
} else {

}
}
break;
default:
return;
}
}

/***
* 手势抬起操作
*
* @param event
*/
public void doActionUp(MotionEvent event) {
if(getAdapter().isEmpty()){
return;
}

if((((int)event.getY())-mStartY)<-45&&getLastVisiblePosition()>=(getCount()-1)){
//加载更多
onClick(footerLayout);
return;
}

mIsRecord = false;// 此时的touch事件完毕,要关闭。
isScroller = true;// ListView可以Scrooler滑动.
// 如果下拉状态处于loading状态.
if (mFirstItemIndex) {
if (mlistViewState != DListViewState.LV_LOADING) {
// 处理相应状态.
switch (mlistViewState) {
// 普通状态
case LV_NORMAL:

break;
// 下拉状态
case LV_PULL_REFRESH:
headerLayout.setPadding(0, -1 * mHeadViewHeight, 0, 0);
mlistViewState = DListViewState.LV_NORMAL;
break;
// 刷新状态
case LV_RELEASE_REFRESH:
headerLayout.setPadding(0, 0, 0, 0);
mlistViewState = DListViewState.LV_LOADING;
headerTextView.setText("正在刷新");
headerProgressBar.setVisibility(View.VISIBLE);
if (handler != null)
handler.upRefresh();// 上拉刷新
break;
}
}
}
}

private int dipTopx(float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值