【Android高级】全部自己实现的下拉刷新功能
2015-12-28 09:51
471 查看
很早之前就接触过下拉刷新的第三方库,貌似大一就用过了,当时也只是用用。
后来很久没有用了,上次用的使用的时候,顺便把源码也看了看,当时也只是看看。
现在时间还算充裕,始终感觉有口气憋着,于是打算靠自己把下拉刷新的功能也出来,这次真要写写了。
写的过程其实不太算顺利,开始把问题想复杂了,嵌套了好多view,导致后面的触摸事件搞得特别复杂,虽然最后能下拉刷出来,但那个效果真的不能再烂了。把我搞得心累的。。。
缓了缓之后,我尝试了一种新思路,直接继承listView,把下拉头放在ListView的headView里面,在开发过程中也遇到不少问题,但想尽一切办法还是基本搞出来了。在项目开发过程中主要遇到下面三个问题:
(1)初始化的适合就要把adpter传进去,不然动画和headView加载会失效。
(2)headView通过headView.setPadding(0, (int) -headHeight, 0, 0);即padding控制滑动位置。
(3)要自定义函数获取listView滚动的高度
public int getMyScrollY() {
View c = this.getChildAt(0);
if (c == null) { return 0; }
int firstVisiblePosition = this.getFirstVisiblePosition();
int top = c.getTop();
return -top + firstVisiblePosition * c.getHeight();
}
下面是源码部分:
【自定义的CustomListView】
public class CustomListView extends ListView {
enum State {
None, Load, Over, Refresh_Down, List_Down, List_Up
}
public interface CustomPullRereshListener {
public void pullUpToRrefreshing();
}
public void setCustomPullRereshListener(CustomPullRereshListener customPullRereshListener) {
this.customPullRereshListener = customPullRereshListener;
}
CustomPullRereshListener customPullRereshListener;
View headView;
float headHeight;
Handler handler;
ImageView rotateImageView;
TextView rotateTextView;
public CustomListView(Context context, AttributeSet attrs) {
super(context, attrs);
headView = (View) LayoutInflater.from(context).inflate(R.layout.head_lay, this, false);
headView.measure(0, 0);
Log.i("tag", headView.getMeasuredHeight() + "--" + headView.getMeasuredWidth() + "--" + headView.getX() + "--" + headView.getY());
rotateImageView = (ImageView) headView.findViewById(R.id.rotate_img);
rotateTextView = (TextView) headView.findViewById(R.id.rotate_tv);
headHeight = headView.getMeasuredHeight();
handler = new Handler();
addHeaderView(headView, null, false);
headView.setPadding(0, (int) -headHeight, 0, 0);
headView.invalidate();
this.setHeaderDividersEnabled(false);
}
public void initAdapter(BaseAdapter adapter) {
setAdapter(adapter);
}
float current_Y;
float bef_Y;
float start_Y;
float index;
State nowState;
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
}
float radio;
public int getMyScrollY() {
View c = this.getChildAt(0);
if (c == null) {
return 0;
}
int firstVisiblePosition = this.getFirstVisiblePosition();
int top = c.getTop();
return -top + firstVisiblePosition * c.getHeight();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
current_Y = event.getY();
bef_Y = current_Y;
start_Y = current_Y;
radio = 1;
nowState = State.None;
stateChange(nowState);
return true;
case MotionEvent.ACTION_MOVE:
current_Y = event.getY();
index = current_Y - bef_Y;
if (index > 20 && index < 100) {
if (getMyScrollY() == 0) {
nowState = State.Refresh_Down;
}
}
if (nowState == State.Refresh_Down) {
radio = Math.abs(current_Y - start_Y) / 300 + 1;
scrollBy(0, -(int) (index / (radio)));
headView.setPadding(0, (int) (index / radio), 0, 0);
bef_Y = current_Y;
return true;
}
break;
case MotionEvent.ACTION_UP:
if (nowState == State.Refresh_Down) {
nowState = State.Load;
stateChange(nowState);
if (customPullRereshListener != null) {
customPullRereshListener.pullUpToRrefreshing();
} else {
refreshComplete();
}
return true;
}
break;
}
return super.onTouchEvent(event);
}
public void refreshComplete() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (nowState == State.Load) {
nowState = State.Over;
stateChange(nowState);
scrollTo(0, 0);
headView.setPadding(0, (int) -headHeight, 0, 0);
}
}
}, 1000);
}
private void stateChange(State state) {
switch (state) {
case Load:
rotateTextView.setText("正在加载......");
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(360);
rotateAnimation.setFillAfter(false);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
rotateAnimation.setInterpolator(new LinearInterpolator());//不停顿
rotateImageView.setAnimation(rotateAnimation);
rotateAnimation.start();
rotateImageView.invalidate();
break;
case Over:
rotateImageView.getAnimation().cancel();
rotateTextView.setText("加载完毕");
break;
case None:
rotateTextView.setText("下拉刷新");
break;
}
}
}
【在Activity中使用】
后来很久没有用了,上次用的使用的时候,顺便把源码也看了看,当时也只是看看。
现在时间还算充裕,始终感觉有口气憋着,于是打算靠自己把下拉刷新的功能也出来,这次真要写写了。
写的过程其实不太算顺利,开始把问题想复杂了,嵌套了好多view,导致后面的触摸事件搞得特别复杂,虽然最后能下拉刷出来,但那个效果真的不能再烂了。把我搞得心累的。。。
缓了缓之后,我尝试了一种新思路,直接继承listView,把下拉头放在ListView的headView里面,在开发过程中也遇到不少问题,但想尽一切办法还是基本搞出来了。在项目开发过程中主要遇到下面三个问题:
(1)初始化的适合就要把adpter传进去,不然动画和headView加载会失效。
(2)headView通过headView.setPadding(0, (int) -headHeight, 0, 0);即padding控制滑动位置。
(3)要自定义函数获取listView滚动的高度
public int getMyScrollY() {
View c = this.getChildAt(0);
if (c == null) { return 0; }
int firstVisiblePosition = this.getFirstVisiblePosition();
int top = c.getTop();
return -top + firstVisiblePosition * c.getHeight();
}
下面是源码部分:
【自定义的CustomListView】
public class CustomListView extends ListView {
enum State {
None, Load, Over, Refresh_Down, List_Down, List_Up
}
public interface CustomPullRereshListener {
public void pullUpToRrefreshing();
}
public void setCustomPullRereshListener(CustomPullRereshListener customPullRereshListener) {
this.customPullRereshListener = customPullRereshListener;
}
CustomPullRereshListener customPullRereshListener;
View headView;
float headHeight;
Handler handler;
ImageView rotateImageView;
TextView rotateTextView;
public CustomListView(Context context, AttributeSet attrs) {
super(context, attrs);
headView = (View) LayoutInflater.from(context).inflate(R.layout.head_lay, this, false);
headView.measure(0, 0);
Log.i("tag", headView.getMeasuredHeight() + "--" + headView.getMeasuredWidth() + "--" + headView.getX() + "--" + headView.getY());
rotateImageView = (ImageView) headView.findViewById(R.id.rotate_img);
rotateTextView = (TextView) headView.findViewById(R.id.rotate_tv);
headHeight = headView.getMeasuredHeight();
handler = new Handler();
addHeaderView(headView, null, false);
headView.setPadding(0, (int) -headHeight, 0, 0);
headView.invalidate();
this.setHeaderDividersEnabled(false);
}
public void initAdapter(BaseAdapter adapter) {
setAdapter(adapter);
}
float current_Y;
float bef_Y;
float start_Y;
float index;
State nowState;
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
}
float radio;
public int getMyScrollY() {
View c = this.getChildAt(0);
if (c == null) {
return 0;
}
int firstVisiblePosition = this.getFirstVisiblePosition();
int top = c.getTop();
return -top + firstVisiblePosition * c.getHeight();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
current_Y = event.getY();
bef_Y = current_Y;
start_Y = current_Y;
radio = 1;
nowState = State.None;
stateChange(nowState);
return true;
case MotionEvent.ACTION_MOVE:
current_Y = event.getY();
index = current_Y - bef_Y;
if (index > 20 && index < 100) {
if (getMyScrollY() == 0) {
nowState = State.Refresh_Down;
}
}
if (nowState == State.Refresh_Down) {
radio = Math.abs(current_Y - start_Y) / 300 + 1;
scrollBy(0, -(int) (index / (radio)));
headView.setPadding(0, (int) (index / radio), 0, 0);
bef_Y = current_Y;
return true;
}
break;
case MotionEvent.ACTION_UP:
if (nowState == State.Refresh_Down) {
nowState = State.Load;
stateChange(nowState);
if (customPullRereshListener != null) {
customPullRereshListener.pullUpToRrefreshing();
} else {
refreshComplete();
}
return true;
}
break;
}
return super.onTouchEvent(event);
}
public void refreshComplete() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (nowState == State.Load) {
nowState = State.Over;
stateChange(nowState);
scrollTo(0, 0);
headView.setPadding(0, (int) -headHeight, 0, 0);
}
}
}, 1000);
}
private void stateChange(State state) {
switch (state) {
case Load:
rotateTextView.setText("正在加载......");
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(360);
rotateAnimation.setFillAfter(false);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
rotateAnimation.setInterpolator(new LinearInterpolator());//不停顿
rotateImageView.setAnimation(rotateAnimation);
rotateAnimation.start();
rotateImageView.invalidate();
break;
case Over:
rotateImageView.getAnimation().cancel();
rotateTextView.setText("加载完毕");
break;
case None:
rotateTextView.setText("下拉刷新");
break;
}
}
}
【在Activity中使用】
public class MainAct extends Activity { HttpExecutor httpExecutor; String urlsArray[] = { "http://cdn.duitang.com/uploads/item/201207/18/20120718215150_QyFQZ.jpeg", "http://p4.qqgexing.com/shaitu/2012/07/04/15/4ff3f5c978a47.jpg", "http://pic28.nipic.com/20130425/11851724_233351407130_2.jpg", "http://pic20.nipic.com/20120502/9783151_111254241000_2.jpg", "http://imglf1.ph.126.net/EeL25lsX85z6c96AwavoTA==/6598268234330966851.jpg", "http://img2.duitang.com/uploads/item/201302/20/20130220145320_esamB.thumb.600_0.jpeg", "http://img.hb.aicdn.com/13f25a84dccc639761eefb17f24c9e6e5a465589194d2-KfLLqS_fw580",//7 "http://pica.nipic.com/2008-01-19/2008119114919476_2.jpg", "http://pic10.nipic.com/20101104/2318721_221323551000_2.jpg", "http://pic33.nipic.com/20130928/4420504_005335593000_2.jpg", "http://pic.nipic.com/2008-06-26/20086261061382_2.jpg", "http://pic4.nipic.com/20090724/3058848_003738705_2.jpg", "http://pic28.nipic.com/20130407/10942662_171131527000_2.jpg", "http://pic10.nipic.com/20101022/5974539_102012063985_2.jpg",//7 "http://pic1a.nipic.com/2008-09-03/20089314315569_2.jpg", "http://pic31.nipic.com/20130703/4383073_091911237144_2.jpg", "http://pic23.nipic.com/20120831/10705080_091651720189_2.jpg", "http://pic27.nipic.com/20130310/10753400_160550558169_2.jpg", "http://pic25.nipic.com/20121108/10222425_165949609136_2.jpg", "http://img3.redocn.com/20140313/20140312_ac2c4a0c509fcf1f6a16pMm5444bqKJa.jpg", "http://pica.nipic.com/2007-10-12/20071012214217571_2.jpg", "http://pic.58pic.com/58pic/13/85/97/97g58PICJtn_1024.jpg", "http://pic12.nipic.com/20110125/5860366_200110540150_2.jpg"};//9 ArrayList<String> urls = new ArrayList<String>(); CustomListView pullToRefreshListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.new_cutom_view_lay); httpExecutor = new HttpExecutor(new Handler()); pullToRefreshListView = (CustomListView) findViewById(R.id.container_lay); final MyAdapter myAdapter = new MyAdapter(); pullToRefreshListView.initAdapter(myAdapter); pullToRefreshListView.setCustomPullRereshListener(new CustomListView.CustomPullRereshListener() { @Override public void pullUpToRrefreshing() { loadDataToList(); myAdapter.notifyDataSetChanged(); pullToRefreshListView.refreshComplete(); } }); pullToRefreshListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.i("tag", "pos:" + position); } }); } public void loadDataToList() { for (int i = 0; i < urlsArray.length; i++) { urls.add(urlsArray[i]); } } class MyAdapter extends BaseAdapter { @Override public int getCount() { return urls.size(); } @Override public Object getItem(int position) { return urls.size(); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { MyHolder myHolder; if (convertView == null) { convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.list_item_lay, null); myHolder = new MyHolder(); myHolder.imageView = (ImageView) convertView.findViewById(R.id.item_img); myHolder.textView = (TextView) convertView.findViewById(R.id.item_tv); convertView.setTag(myHolder); } myHolder = (MyHolder) convertView.getTag(); myHolder.imageView.setImageResource(R.drawable.loading);//BitmapFactory.decodeResource(getResources(), R.drawable.loading)); myHolder.textView.setText("loading..."); myHolder.imageView.setTag(urls.get(position)); myHolder.textView.setTag(urls.get(position) + "_tv"); httpExecutor.loadImage(urls.get(position), myHolder, position); return convertView; } } }
相关文章推荐
- android AppWidgetProvider讲解
- Android手机怎么会越用越卡?真相就在这里
- Android WebView远程执行代码漏洞浅析
- Android自动化压力测试图解教程——Monkey工具
- vlc for android demo
- Android 5.0(包含5.0以下版本) 获取栈顶应用程序包名
- Android开发:使用JNI读取应用签名
- android-Managing the Activity Lifecycle
- [IMX6Q]Android版本如何获取u-boot源代码
- Realm for Android快速入门教程
- 【Android开发】wifi开关与wifi连接(密码连接)
- Android 权限
- Android AsyncTask详解
- Android文件浏览器
- Android反射例子的学习
- android开发游记:弹出窗和底部弹出窗的实现和动画效果
- Android---再按一次退出页面
- 《Android源码设计模式解析与实战》读书笔记(十二)
- Android Kitkat 如何让系统永久不休眠
- Android:Attribute is missing the Android namespace prefix