Android自定义控件之仿美团下拉刷新
2016-02-24 16:04
495 查看
美团的下拉刷新分为三个状态:
第一个状态为下拉刷新状态(pull to refresh),在这个状态下是一个绿色的椭圆随着下拉的距离动态改变其大小。
第二个部分为放开刷新状态(release to refresh),在这个状态下是一个帧动画,效果为从躺着变为站起来的动画。
第三个部分为刷新状态(refreshing),在这个状态下也是一个帧动画,是摇头的动画。
其中第二和第三个状态很简单,就是两个帧动画,第一个状态我们可以用自定义View来实现。
第一个状态的实现:
我们的思路是:当前这个椭圆形有一个进度值,这个进度值从0变为1,然后对这个椭圆形进行缩放,我们可以使用自定义View来实现这个效果,我们先来用一个SeekBar来模仿一下下拉距离的进度我们解压美团apk后拿到这张图片:
public class MeiTuanRefreshFirstStepView extends View{ private Bitmap initialBitmap; private int measuredWidth; private int measuredHeight; private Bitmap endBitmap; private float mCurrentProgress; private Bitmap scaledBitmap; public MeiTuanRefreshFirstStepView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public MeiTuanRefreshFirstStepView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public MeiTuanRefreshFirstStepView(Context context) { super(context); init(context); } private void init(Context context) { //这个就是那个椭圆形图片 initialBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_image)); //这个是第二个状态娃娃的图片,之所以要这张图片,是因为第二个状态和第三个状态的图片的大小是一致的,而第一阶段 //椭圆形图片的大小与第二阶段和第三阶段不一致,因此我们需要根据这张图片来决定第一张图片的宽高,来保证 //第一阶段和第二、三阶段的View的宽高一致 endBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_end_image_frame_05)); } /** * 重写onMeasure方法主要是设置wrap_content时 View的大小 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //根据设置的宽度来计算高度 设置为符合第二阶段娃娃图片的宽高比例 setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(widthMeasureSpec)*endBitmap.getHeight()/endBitmap.getWidth()); } /** * 当wrap_content的时候,宽度即为第二阶段娃娃图片的宽度 * @param widMeasureSpec * @return */ private int measureWidth(int widMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widMeasureSpec); int mode = MeasureSpec.getMode(widMeasureSpec); if (mode == MeasureSpec.EXACTLY){ result = size; }else{ result = endBitmap.getWidth(); if (mode == MeasureSpec.AT_MOST){ result = Math.min(result,size); } } return result; } /** * 在onLayout里面获得测量后View的宽高 * @param changed * @param left * @param top * @param right * @param bottom */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); measuredWidth = getMeasuredWidth(); measuredHeight = getMeasuredHeight(); //根据第二阶段娃娃宽高 给椭圆形图片进行等比例的缩放 scaledBitmap = Bitmap.createScaledBitmap(initialBitmap, measuredWidth,measuredWidth*initialBitmap.getHeight()/initialBitmap.getWidth(), true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //这个方法是对画布进行缩放,从而达到椭圆形图片的缩放,第一个参数为宽度缩放比例,第二个参数为高度缩放比例, canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight/2); //将等比例缩放后的椭圆形画在画布上面 canvas.drawBitmap(scaledBitmap,0,measuredHeight/4,null); } /** * 设置缩放比例,从0到1 0为最小 1为最大 * @param currentProgress */ public void setCurrentProgress(float currentProgress){ mCurrentProgress = currentProgress; }
然后在Activity里面:
第二个状态的实现:
第二个状态是一个帧动画,我们为了保证View大小的统一,我们也进行自定义View,这个自定义View很简单,只是为了和第一阶段View的宽高保证一致即可第三个状态的实现:
和第二个状态同理,我们也通过自定义View来确保三个状态的View的宽高保持一致?
下拉刷新的实现:
首先我们要定义好几个状态,下拉刷新有这样几个状态:DONE:隐藏的状态
PULL_TO_REFRESH:下拉刷新的状态
RELEASE_TO_REFRESH:松开刷新的状态
REFRESHING:正在刷新的状态
一切准备就绪,在Activity中使用:
public class MainActivity extends Activity implements OnMeiTuanRefreshListener{ private MeiTuanListView mListView; private List<string> mDatas; private ArrayAdapter<string> mAdapter; private final static int REFRESH_COMPLETE = 0; /** * mHandler运行在主线程,因为setOnRefreshComplete需要改变ui,必须在主线程去改变ui * 所以在handleMessage中调用mListView.setOnRefreshComplete(); */ private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case REFRESH_COMPLETE: mListView.setOnRefreshComplete(); mAdapter.notifyDataSetChanged(); mListView.setSelection(0); break; default: break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (MeiTuanListView) findViewById(R.id.listview); String[] data = new String[]{hello world,hello world,hello world,hello world, hello world,hello world,hello world,hello world,hello world, hello world,hello world,hello world,hello world,hello world,}; mDatas = new ArrayList<string>(Arrays.asList(data)); mAdapter = new ArrayAdapter<string>(this, android.R.layout.simple_list_item_1,mDatas); mListView.setAdapter(mAdapter); mListView.setOnMeiTuanRefreshListener(this); } @Override public void onRefresh() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); mDatas.add(0, new data); mHandler.sendEmptyMessage(REFRESH_COMPLETE); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } }
相关文章推荐
- windows下 更新 android studio SDK 到最新版本 解决方案
- Android样式之drawable
- Android中基于XMPP协议实现IM聊天程序与多人聊天室
- Android性能优化之Bitmap的内存优化
- Android 欢迎引导页的魅力
- Android 快速开发框架:推荐10个框架
- Android命令行查看内存情况
- Android BroadcastReceiver
- 2015年Android 开发有哪些新技术出现?
- 直接拿来用!最火的Android开源项目整理
- 使用android.view.TouchDelegate扩大View的触摸点击区域
- Android记录20-获取缓存大小和清除缓存功能
- (转)Android 弹软键盘时listview的变化控制
- Android系统添加定制的文字
- Android学习之计算2个日期之间有多少年月日
- Android屏幕设置
- Android开发中minSdkVersion、targetSdkVersion、maxSdkVersion和project.properties中target API level
- android activity切换动画的简单办法
- SQLITE在ANDROID上的一个BUG
- Android 依据变量来获得资源R中的id值