@myron-lee
2015-03-20T01:37:11.000000Z
字数 3604
阅读 1919
Blog
打算做个阅读类的 App,想要模仿豆瓣一刻的上拉翻页效果。做了一些 search,发现跟 ListView 的 PullToRefresh 实现是类似的。而后者已经用过很多次了,还是不会改造。所以,尽管实现的不够完善,还是要自己动手,否则永远不明白其中的原理。从最简单的做起,先完成上拉翻页的效果。自己动手系列的custom view 都不是拿来用的,因为很多情况没有考虑,只把最基本的功能实现了,使得代码量很小,从而看得出原理。
Android-PullToRefresh
Android 下拉刷新框架实现
PullToRefreshView
所谓上拉翻页,其实是上拉触发翻页。上拉用 PullToRefresh 实现,翻页用 fragment transition animation 实现。简单实现上拉翻页,只需要做两点:
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);}@Overrideprotected 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*/@Overridepublic 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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Medium Text"android:textAppearance="?android:attr/textAppearanceMedium"android:layout_marginTop="-100dp" /><ScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid: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><TextViewandroid: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 非常重要。