[关闭]
@myron-lee 2015-03-20T01:37:11.000000Z 字数 3604 阅读 1819

自己动手(二)──PullToRefresh之上拉翻页

Blog


前言

打算做个阅读类的 App,想要模仿豆瓣一刻的上拉翻页效果。做了一些 search,发现跟 ListView 的 PullToRefresh 实现是类似的。而后者已经用过很多次了,还是不会改造。所以,尽管实现的不够完善,还是要自己动手,否则永远不明白其中的原理。从最简单的做起,先完成上拉翻页的效果。自己动手系列的custom view 都不是拿来用的,因为很多情况没有考虑,只把最基本的功能实现了,使得代码量很小,从而看得出原理。

参考链接

Android-PullToRefresh
Android 下拉刷新框架实现
PullToRefreshView

效果图

原理

所谓上拉翻页,其实是上拉触发翻页。上拉用 PullToRefresh 实现,翻页用 fragment transition animation 实现。简单实现上拉翻页,只需要做两点:

关键源码

  1. public class PullToTurnPageLayout extends LinearLayout {
  2. private final static float SCROLL_RATIO = 0.35f;
  3. private View contentView;
  4. private View footerView;
  5. private float lastY;
  6. private ScrollView scrollView;
  7. private int footerViewHeight;
  8. private TextView footerTextView;
  9. public PullToTurnPageLayout(Context context) {
  10. super(context);
  11. }
  12. public PullToTurnPageLayout(Context context, AttributeSet attrs) {
  13. super(context, attrs);
  14. }
  15. public PullToTurnPageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  16. super(context, attrs, defStyleAttr);
  17. }
  18. @Override
  19. protected void onFinishInflate() {
  20. super.onFinishInflate();
  21. contentView = getChildAt(0);
  22. footerView = getChildAt(1);
  23. footerView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
  24. footerViewHeight = footerView.getMeasuredHeight();
  25. LayoutParams layoutParams = (LayoutParams) footerView.getLayoutParams();
  26. layoutParams.height = footerViewHeight;
  27. footerView.setLayoutParams(layoutParams);
  28. scrollView = (ScrollView) contentView;
  29. footerTextView = (TextView) footerView;
  30. }
  31. /**
  32. * should get touch event from here, otherwise you can not scroll out the footerView closely after scroll the scrollview
  33. * @param event
  34. * @return
  35. */
  36. @Override
  37. public boolean dispatchTouchEvent(MotionEvent event) {
  38. if (scrollView.getScrollY() >= scrollView.getChildAt(0).getMeasuredHeight()- scrollView.getHeight()){
  39. switch (event.getAction()) {
  40. case MotionEvent.ACTION_DOWN:
  41. break;
  42. case MotionEvent.ACTION_MOVE:
  43. float dy = event.getY() - lastY;
  44. scrollBy(0, (int) (-dy*SCROLL_RATIO));
  45. break;
  46. case MotionEvent.ACTION_UP:
  47. case MotionEvent.ACTION_CANCEL:
  48. if (getScrollY() >= footerViewHeight){
  49. if (footerListener != null){
  50. footerListener.onTrigger();
  51. }
  52. } else {
  53. scrollTo(0, 0);
  54. }
  55. break;
  56. }
  57. if (getScrollY() >= footerViewHeight){
  58. footerTextView.setText("松开翻页");
  59. } else {
  60. footerTextView.setText("上拉翻页");
  61. }
  62. lastY = event.getY();
  63. }
  64. return super.dispatchTouchEvent(event);
  65. }
  66. private FooterListener footerListener;
  67. public void setFooterListener(FooterListener footerListener) {
  68. this.footerListener = footerListener;
  69. }
  70. public static interface FooterListener {
  71. public void onTrigger();
  72. }
  73. }

不理解的地方

先用LinearLayout 做的实验

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <TextView
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"
  9. android:text="Medium Text"
  10. android:textAppearance="?android:attr/textAppearanceMedium"
  11. android:layout_marginTop="-100dp" />
  12. <ScrollView
  13. android:layout_width="match_parent"
  14. android:layout_height="wrap_content">
  15. <TextView
  16. android:id="@+id/textView6"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:text="a lot of text, leave out here"
  20. android:textAppearance="?android:attr/textAppearanceLarge" />
  21. </ScrollView>
  22. <TextView
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:text="Medium Text"
  26. android:textAppearance="?android:attr/textAppearanceMedium" />
  27. </LinearLayout>

非常不理解的是,在 ScrollView 内容很多的情况下,底部 TextView的 layout_height 设为 wrap_content 的话,永远显示不出来,即便设置顶部 TextView 的 topMargin 为负也不行。可能是因为View Tree 会判断没有底部 TextView 的位置了,wrap_content 也没用。所以手动设置 footerView 的 height 非常重要。

弯路

TODO

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注