自己动手(二)──PullToRefresh之上拉翻页(3)
来源:互联网 发布:内锥形螺纹编程实例 编辑:程序博客网 时间:2024/06/16 11:07
前言
其实,上拉作为一个手势可以和很多动作关联,不仅仅局限于翻页。我的实现里面很多东西写的比较死,比如其实bottom view其实可以由使用者创建,bottom view在上拉过程中状态的改变也可以定制,通过addView加入到PullToRefresh容器中,这样可以提供更多灵活性。即,可以定义一个AbsBottomView的虚基类,它会有一些诸如onFinish,onRelease, onPull之类的函数,供PullToRefresh容器调用。
改进
- 处理一个手势分两半,一半container处理、一半content处理的情况。即,处理权从content变到container,手动给content发个cancel event,处理权从container变到content,手动给conten发个down event。
- 让容器继承自FrameLayout
- 使得content view可以是任意类型的view,增强通用性
- 用Scroller工具类替代自定义Animation来实现平滑移动
- 给变量、函数起个好名字
完整demo
github任意门
相关源码
public class PTRFrameLayout extends FrameLayout { private final static float SCROLL_RATIO = 0.35f; private static final long ROTATE_ANIM_DURATION = 180; enum STATE {GUIDE_USER_PULL, GUIDE_USER_RELEASE} private STATE footerViewState = STATE.GUIDE_USER_PULL; private View contentView; private View footerView; private float lastY = -1; private int footerViewHeight; private TextView footerTextView; private Animation rotateUpAnim; private Animation rotateDownAnim; private ImageView arrowImageView; private Scroller scroller; public PTRFrameLayout(Context context) { super(context); init(); } public PTRFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public PTRFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { scroller = new Scroller(getContext(), new DecelerateInterpolator(1.6F)); rotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateUpAnim.setDuration(ROTATE_ANIM_DURATION); rotateUpAnim.setFillAfter(true); rotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateDownAnim.setDuration(ROTATE_ANIM_DURATION); rotateDownAnim.setFillAfter(true); } @Override protected void onFinishInflate() { super.onFinishInflate(); contentView = getChildAt(0); footerView = getChildAt(1); arrowImageView = (ImageView) findViewById(R.id.iv_ptr_arrow); footerTextView = (TextView) findViewById(R.id.tv_ptr_operation_hint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); footerViewHeight = footerView.getMeasuredHeight(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { contentView.layout(left, top, right, bottom); footerView.layout(left, bottom, right, bottom + footerView.getMeasuredHeight()); } /** * should get touch event from here, otherwise you can not scroll out the footerView closely after scroll the scrollview * * @param event * @return */ @Override public boolean dispatchTouchEvent(MotionEvent event) { if (lastY == -1) { lastY = event.getY(); } float dy = event.getY() - lastY; lastY = event.getY(); if (getScrollY() != 0 || (dy < 0 && !contentCanScrollUp())) { //content scroll end, ptr container scroll begin, //send a cancel event to content view, for content view's sake if (getScrollY() == 0) { MotionEvent cancelEvent = MotionEvent.obtain(event); cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (event.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); super.dispatchTouchEvent(cancelEvent); } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: //make sure getScrollY() >= 0, aka never let top show blank area int calibratedScrollY = (int) (-dy * SCROLL_RATIO); if ((getScrollY() - dy * SCROLL_RATIO) < 0) { calibratedScrollY = -getScrollY(); } scrollBy(0, calibratedScrollY); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (getScrollY() >= footerViewHeight) { if (PTRListener != null) { PTRListener.onTrigger(); } } release(); break; } updateFooterViewState(); //ptr container scroll end, content scroll begin, //send a down event to content view, so it can recognize this second part of the gesture if (getScrollY() == 0) { MotionEvent downEvent = MotionEvent.obtain(event); downEvent.setAction(MotionEvent.ACTION_DOWN | event.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT); downEvent.setLocation(event.getX(), event.getY()); super.dispatchTouchEvent(downEvent); } } return super.dispatchTouchEvent(event); } private void updateFooterViewState() { if (getScrollY() >= footerViewHeight && footerViewState != STATE.GUIDE_USER_RELEASE) { footerTextView.setText("let it go ~ baby"); arrowImageView.startAnimation(rotateDownAnim); footerViewState = STATE.GUIDE_USER_RELEASE; } else if (getScrollY() < footerViewHeight && footerViewState != STATE.GUIDE_USER_PULL) { footerTextView.setText("pull ~ baby"); arrowImageView.startAnimation(rotateUpAnim); footerViewState = STATE.GUIDE_USER_PULL; } } private void release() { scroller.startScroll(0, getScrollY(), 0, -getScrollY()); invalidate();//this will make computeScroll() get called } @Override public void computeScroll() { if (scroller.computeScrollOffset()){ scrollTo(0, scroller.getCurrY()); } } private boolean contentCanScrollUp() { if (contentView instanceof AdapterView<?>) { AdapterView<?> adapterView = (AdapterView<?>) contentView; if (adapterView.getLastVisiblePosition() == adapterView.getCount() - 1 && adapterView.getChildAt(adapterView.getChildCount() - 1).getBottom() <= adapterView.getHeight()) { Log.e("", "adapterView content can not scroll up anymore"); return false; } else { return true; } } else { if (contentView.getScrollY() >= contentView.getMeasuredHeight() - contentView.getHeight()) { return false; } else { return true; } } } private PTRListener PTRListener; public void setPTRListener(PTRListener PTRListener) { this.PTRListener = PTRListener; } public static interface PTRListener { public void onTrigger(); }}
0 0
- 自己动手(二)──PullToRefresh之上拉翻页(3)
- 自己动手(二)──PullToRefresh之上拉翻页(1)
- 自己动手(二)──PullToRefresh之上拉翻页(2)
- PullToRefresh之GridView(上下拉刷新)
- input之上层(二)
- pulltorefresh工程研究(二)
- android初学-----PullToRefresh 上拉刷新 (ListView)
- Android PullToRefresh (ListView GridView 上下拉刷新) 使用详解
- Android PullToRefresh (GridView 下拉刷新上拉加载)
- Listview(PullToRefresh ) 下拉刷新,上拉加载
- pullToRefresh的使用(1) ListView的上拉加载
- 自己动手写俄罗斯方块(二)
- 自己动手写操作系统(二)
- pulltorefresh+recycleview 实现的瀑布流(带下拉刷新,上拉加载更多)
- Android 开发学习手记(二):PullToRefresh如何滚动到最顶部?以及PullToRefresh的实质。
- 在Hadoop YARN之上配置Spark集群(二)
- 自己动手做WEB控件(二)
- 自己动手做图片搜索引擎(二)
- 如何设定tomcat启动时JVM内存大小,以免出现java.lang.OutOfMemoryError
- 深入了解MySQL
- 【java】this()与super()使用详解
- HTML5基础17----HTML5背景
- Leetcode|Reverse Words in a String
- 自己动手(二)──PullToRefresh之上拉翻页(3)
- 大小写转换
- HTML5——Day1
- iOS中自定义UIImageView用TargetAction模式实现关灯小游戏
- HTML5基础18----HTML5实体
- C++学习,总结二(模拟鼠标键盘操作和进程之间的通信)
- Java 内存泄露 与 Reference
- 5. php 基本数据类型
- hibernate和sleep的区别