PS:Struggle for a better future
学习内容:
1.PullToRefrech下拉刷新的实现...
不得不说AndBase这个开源框架确实是非常的强大..把大部分的东西都进行了封装..提供给我们去使用..有些框架其实也被封装了起来...就拿PullToRefrech下拉刷新,还有SlidingMenu来说滑动菜单的实现都被完整的封装在了AndBase内部...提供给我们方便去实现更好的效果...
PullToRefrech,下拉刷新..这个效果在绝大多数使用app貌似都使用的到..一个页面的、如果数据太多必然进行下拉..那么下拉之后就需要显示新的数据信息..这就是下拉刷新的完整体现.也可以说这种效果能够给用户一个更加良好的体验..那么我们看看下拉刷新到底是如何实现的..
1.普通View的PullReferch
无论是普通View的下拉刷新还是ListView,还是GridView..下拉刷新实现的原理基本都是相同的..只不过实现上有一些简单的细节不太一样而已...首先先看看普通View的下拉刷新..实现普通下拉刷新需要使用到AbPullView, AbPullView extends ScollView 可滑动视图...不难想象的一件事情就是无论是怎样进行滑动..其实都是对布局的覆盖..
手机的屏幕大小是有限的...因此无论是怎样进行滑动..都是一层布局去覆盖原来的那层布局..原来的那层布局会被直接销毁..如果按照正常思路去想,那么就算是View被销毁了...那么自然有记录了这次布局的相关数据...当这些被销毁的布局需要再次显示的时候,那么直接调用记录数据就可以了..没有必要再建立新的布局..由于是AndBase内部把这个视图已经封装好了因此我们需要进行相关的引用..说白了就是需要进行动态的布局...因此布局文件中,需要这样去进行书写..我们通过获取ID的方式进行动态的布局..
<com.ab.view.pullview.AbPullView android:id="@+id/mPullView" android:layout_width="fill_parent" android:layout_height="fill_parent"> </com.ab.view.pullview.AbPullView>
获取到了ID之后..通过动态加载xml数据..就可以设置好下拉需要显示的相关View..设置的方式其实就是一行代码就能解决的事情..
mAbPullView.getHeaderView().setHeaderProgressBarDrawable(this.getResources().getDrawable(R.drawable.progress_circular));
这个方式就是设置顶部下拉刷新的一个背景显示...这里我设置了一个动态的效果...R.drawable.progress_circular...
<!-- 单帧动画旋转功能的实现 --> <!-- 持续时间:两秒 起始角度:0度 定义动画的旋转样式..起始和结束都减速..中间过程加速.. 偏移量:顶部和左部 重复的样式:重新开始 末端角度:360度 背景设置:drawable--> <?xml version="1.0" encoding="utf-8"?> <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="200" android:fromDegrees="0.0" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:pivotX="50.0%" android:pivotY="50.0%" android:repeatMode="restart" android:toDegrees="360.0" android:drawable="@drawable/progress_loading2"> </animated-rotate>
上面的这些过程都是设置下拉时需要显示的View数据..并没有真正涉及到下拉的过程..说白了这个就是下拉后需要发生的事情..而真正想要实现下拉..少不了监听事件的设置..有了对下拉的监听..系统才能够对下拉进行相关的响应..响应事件的绑定..
mAbPullView.setAbOnRefreshListener(new AbOnRefreshListener(){ @Override public void onRefresh() { mAbTaskQueue.execute(item); //下拉时需要执行的事件.. } });
绑定上了监听之后..当我们在屏幕上进行下拉的时候..那么就会有事件进行响应了..这里我设置任务是一个异步线程任务...我们可以在这个任务中设置需要执行的事件..然后将事物放入到任务执行队列当中..那么任务就会在下拉的这个时间段内被执行..然后更新在UI界面上..
final AbTaskItem item = new AbTaskItem(); item.listener = new AbTaskListener() { @Override public void update() { //当任务完成之后..那么停止刷新..也就表示下拉时出现的视图需要被隐藏了... removeProgressDialog(); mAbPullView.stopRefresh(); //停止刷新.. } @Override public void get() { try { Thread.sleep(1000); //这里是任务执行的过程... } catch (Exception e) { } }; };
这样通过几个简单的过程就可以完成普通View的下拉刷新...这个的源码我并没有进行特别深入的研究...其实关键地方就是ScollView 和 FrameLayout..总体的思想我也说过了..视图无论是滑动还是下拉刷新原理就是这样...就是View的覆盖..如果有更有兴趣的..可以去研究研究这两个类的源码...
2.ListView下拉刷新的实现...
ListView下拉刷新,这个在绝大多数的app中都必然会使用到..就拿我们的博客园app来说吧..博客的放入在屏幕上的显示是有限的..那么如果我们想要看到更多的博客文章..那么无非需要下拉刷新加载更多数据,或者是使用分页的方式去显示更多的数据..博客园的app是下拉刷新来实现的..用过的人还是非常清楚的..因此ListView的下拉刷新还是非常的重要的..必须要进行掌握的...
AndBase仍然把一些类进行了封装..提供给我们进行使用..去实现ListView的下拉刷新..原理基本是相同的..需要使用AbPullListView extends ListView implements OnScollListener在继承了ListView的情况下同时也就实现了滚动监听..下面这个接口是在为ListView设置监听后需要实现的方法...方法的实现由我们去实现..这个类仅仅提供了在下拉或上啦后需要做的事情..并没有涉及到滑动的过程...
public interface AbOnListViewListener { /** * On refresh. */ public void onRefresh(); /** * On load more. */ public void onLoadMore(); }
滑动的过程是由于AbPullListView实现了OnTouchEvent方法..OnTouchEvent表示触摸事件监听...当在屏幕上发生按下,抬起,移动等操作时需要执行..这也就是对滑动事件的一个监听设置..没了这个方法..我们怎么滑动屏幕都是徒劳..那么当发生了上拉或者是下拉就会去执行相应的监听事件..这个上拉或者是下拉的过程是通过滑动的坐标值来确定的..这里就涉及到了OnTouchEvent的源码..源码的实现也比较简单...大体的东西还是比较清晰的..
@Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { //对事件的判断.. case MotionEvent.ACTION_DOWN: //按下操作.. mLastY = ev.getRawY(); //获取数值坐标.. break; case MotionEvent.ACTION_MOVE: //移动操作.. final float deltaY = ev.getRawY() - mLastY; //原始值减掉最终值.. mLastY = ev.getRawY(); //获取原始值.. if (mEnablePullRefresh && getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) { //这里是对坐标的判断过程..if条件表示满足上拉条件.. updateHeaderHeight(deltaY / OFFSET_RADIO); } else if (mEnablePullLoad && !mPullLoading && getLastVisiblePosition() == mTotalItemCount - 1 && deltaY<0) { //这个表示下拉过程.. startLoadMore(); } break; case MotionEvent.ACTION_UP: //抬起操作的执行过程.. mLastY = -1; if (getFirstVisiblePosition() == 0) { //需要刷新的条件 if (mEnablePullRefresh && mHeaderView.getVisiableHeight() >= mHeaderViewHeight) { mPullRefreshing = true; mHeaderView.setState(AbListViewHeader.STATE_REFRESHING); if (mListViewListener != null) { //刷新 mListViewListener.onRefresh(); } } if(mEnablePullRefresh){ //弹回 resetHeaderHeight(); } } break; default: break; } return super.onTouchEvent(ev); }
那么有了触摸事件的监听之后..当触摸事件发生之后就可以执行相关的监听事件..这样就可以去执行下拉和上拉过程中需要执行的任务了...那么现在就说一下ListView实现下拉刷新的过程...它的布局文件其实也是和普通View的下拉定义一样..
<com.ab.view.pullview.AbPullListView android:id="@+id/mListView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cacheColorHint="#00000000" android:divider="@drawable/list_divider" android:dividerHeight="1dip" android:fastScrollEnabled="true"> </com.ab.view.pullview.AbPullListView>
我们需要获取它的ID信息..然后再进行动态布局..这就是ListView的刷新过程..首先我们需要允许它能够进行下拉和上拉的操作..否则是无法滑动的..然后设置下拉时显示的东西..我这里是定义了一个动画效果..表示当前的这个View中的东西要实现旋转效果..效果就是普通View中定义的那个效果..
//获取ListView对象 mAbPullListView = (AbPullListView)this.findViewById(R.id.mListView); //打开关闭下拉刷新加载更多功能 mAbPullListView.setPullRefreshEnable(true); mAbPullListView.setPullLoadEnable(true); //设置进度条的样式 mAbPullListView.getHeaderView().setHeaderProgressBarDrawable(this.getResources().getDrawable(R.drawable.progress_circular)); mAbPullListView.getFooterView().setFooterProgressBarDrawable(this.getResources().getDrawable(R.drawable.progress_circular));
然后需要设置相关的监听事件...监听事件就需要重写这两个方法了..前面已经涉及到了这两个方法..就不再进行细说了..一个方法表示的是上拉过程需要进行重新刷新视图,一个表示的是下拉刷新需要加载更多的视图..两个方法..我们需要自定义去实现..
mAbPullListView.setAbOnListViewListener(new AbOnListViewListener(){ @Override public void onRefresh() { mAbTaskQueue.execute(item1); } @Override public void onLoadMore() { mAbTaskQueue.execute(item2); } });
我自己定义了两个异步任务..这两个异步任务用于对数据进行下载的一个操作..那么数据在下载之后是需要更新到ListView中的Item上的..那么Item的数据更新就需要适配器来完成了..因此ListView的适配器不可或缺的一个重要部分..在适配器内部去设置相关样式的显示..当发生下拉或者是上拉等操作的时候..我们去唤醒适配器去更新数据就可以了..更新数据的方法调用..
myListViewAdapter.notifyDataSetChanged();
在这里我只简单的说了一下原理...这个就是任务代码的设置..
final AbTaskItem item1 = new AbTaskItem(); item1.listener = new AbTaskListener() { @Override public void update() { removeProgressDialog(); list.clear(); if(newList!=null && newList.size()>0){ list.addAll(newList); myListViewAdapter.notifyDataSetChanged(); newList.clear(); } mAbPullListView.stopRefresh(); } @Override public void get() { try { Thread.sleep(1000); currentPage = 1; newList = new ArrayList<Map<String, Object>>(); Map<String, Object> map = null; for (int i = 0; i < pageSize; i++) { map = new HashMap<String, Object>(); map.put("itemsIcon",mPhotoList.get(new Random().nextInt(mPhotoList.size()))); map.put("itemsTitle", "item"+(i+1)); map.put("itemsText", "item..."+(i+1)); newList.add(map); } } catch (Exception e) { } }; };
总体的过程就是这样..想要做出更好的效果..我们就需要放入我们自己的思想..就能够做出更好的下拉效果了...
3.GridView 下拉刷新..
GridView网格视图..视图以网格的形式进行展现..每一个网格都是一个子视图..原理和ListView基本相同..只不过ListView是一行行的显示..GridView是一块块的去显示..少不了适配器的使用..只要我们获取到网格中的子选项..然后为每一个子选项设置样式..就可以完成一个网格View的设置...网格View的使用也应该不少..只要我们的设置合理..同样能够做出非常漂亮的网格视图..
GridView采用的方式就不是FrameLayout了..它使用的是线性布局..AbPullGridView extends AbBaseGridView implements OnScollListener, OnTouchListener.. AbBaseGridView是继承了LinearLayout..原理采用线性布局的方式将视图进行展示..通过实现滚动监听和触摸监听就能够实现滚动..以及触摸事件的监听设置..有兴趣的还是可以去研究一下源码的实现过程..我就只说一下其中的调用方式..
布局的定义方式仍然是差不多的..仍然是获取ID,然后通过动态加载的方式进行数据的加载..
<com.ab.view.pullview.AbPullGridView android:id="@+id/mPhotoGridView" android:layout_width="match_parent" android:layout_height="match_parent"> <com.ab.view.pullview.AbPullGridView/>
调用的过程和ListView基本相同..
mAbPullGridView = (AbPullGridView)findViewById(R.id.mPhotoGridView); //开关默认打开 mAbPullGridView.setPullRefreshEnable(true); mAbPullGridView.setPullLoadEnable(true); //设置进度条的样式 mAbPullGridView.getHeaderView().setHeaderProgressBarDrawable(this.getResources().getDrawable(R.drawable.progress_circular)); mAbPullGridView.getFooterView().setFooterProgressBarDrawable(this.getResources().getDrawable(R.drawable.progress_circular)); mGridView = mAbPullGridView.getGridView(); mGridView.setColumnWidth(150); //设置列的宽度.. mGridView.setGravity(Gravity.CENTER); //对齐方式为中央对其.. mGridView.setHorizontalSpacing(5); //设置水平间距.. mGridView.setNumColumns(GridView.AUTO_FIT); //列的数量为自适应屏幕为限制.. mGridView.setPadding(5, 5, 5, 5); //设置间距.. mGridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); mGridView.setVerticalSpacing(5); //GridView之间的垂直间距..
只是GridView的子选项需要我们设置更多的东西..需要设置子选项的排列以及显示方式..设置好了一个子选项的排列方式,那么其他所有的子选项会按照这同一种方式显示在屏幕之上..这样只是设置好了排布的问题..具体需要显示的东西我们还是需要通过使用适配器来安排子选项需要显示的东西..
同样滑动之后需要执行的监听事件我们是需要进行重写的..
mAbPullGridView.setAbOnListViewListener(new AbOnListViewListener() { @Override public void onRefresh() { //第一次下载数据 mAbTaskQueue.execute(item1); } @Override public void onLoadMore() { mAbTaskQueue.execute(item2); } });
同时我们也可以设置子选项被点击时设置的相关监听..通过设置子选项的监听..可以通过触发子选项执行更多的操作..忘记说了..ListView也是可以触发子选项的监听事件的..比较简单就没必要再贴代码了...
mAbPullGridView.getGridView().setOnItemClickListener(new OnItemClickListener(){ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { showToast(""+position); } });
这里的异步任务我也就不再进行粘贴了..和ListVIew基本都是相同的..当任务执行完毕之后..通过唤醒适配器去更新数据信息就可以完成了..这样就实现了PullToRefrech下拉刷新..我们知道了调用过程之后..就能够通过自己定义的方式去设置更加良好的刷新效果..调用的过程不是很难..真正难的是我们自己的思想..如何设置出更加良好的UI才是更加重要的..