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

前言

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

参考链接

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

效果图

这里写图片描述

原理

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

  • 设置 footer view 的高度 programmly
  • 随手指移动 scroll your custom view

关键源码

public class PullToTurnPageLayout extends LinearLayout {

    private final static float SCROLL_RATIO = 0.35f;

    private View contentView;
    private View footerView;

    private float lastY;
    private ScrollView scrollView;
    private int footerViewHeight;
    private TextView footerTextView;

    public PullToTurnPageLayout(Context context) {
        super(context);
    }
    public PullToTurnPageLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public PullToTurnPageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        contentView = getChildAt(0);
        footerView = getChildAt(1);

        footerView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

        footerViewHeight = footerView.getMeasuredHeight();
        LayoutParams layoutParams = (LayoutParams) footerView.getLayoutParams();
        layoutParams.height = footerViewHeight;
        footerView.setLayoutParams(layoutParams);

        scrollView = (ScrollView) contentView;
        footerTextView = (TextView) footerView;
    }

    /**
     * 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 (scrollView.getScrollY() >= scrollView.getChildAt(0).getMeasuredHeight()- scrollView.getHeight()){
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    float dy = event.getY() - lastY;
                    scrollBy(0, (int) (-dy*SCROLL_RATIO));
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                     if (getScrollY() >= footerViewHeight){
                         if (footerListener != null){
                             footerListener.onTrigger();
                         }
                     } else {
                         scrollTo(0, 0);
                     }
                    break;
            }

            if (getScrollY() >= footerViewHeight){
                footerTextView.setText("松开翻页");
            } else {
                footerTextView.setText("上拉翻页");
            }

            lastY = event.getY();
        }

        return super.dispatchTouchEvent(event);
    }

    private FooterListener footerListener;

    public void setFooterListener(FooterListener footerListener) {
        this.footerListener = footerListener;
    }

    public static interface FooterListener {
        public void onTrigger();
    }
}

不理解的地方

先用LinearLayout 做的实验

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_marginTop="-100dp" />
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/textView6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="a lot of text, leave out here"
            android:textAppearance="?android:attr/textAppearanceLarge" />
    </ScrollView>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

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

弯路

  • 因为没有给 PullToTurnPage 继承的 LinearLayout设置 orientation,footer view 一直显示不出来

TODO

  • 解决先上拉再下拉时的 bug
  • 加入箭头动画
  • 加入下拉翻页
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值