效果图
项目结构:
TBLayout中
package com.taobao.detailview; import android.annotation.SuppressLint; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.Scroller; //com.taobao.detailview.TBLayout public class TBLayout extends LinearLayout { private OnPullListener pullListener; private OnPageChangedListener ctListener; public void setOnPullListener(OnPullListener listener) { this.pullListener = listener; } public void setOnContentChangeListener(OnPageChangedListener ler) { this.ctListener = ler; } private View mHeader; private View mFooter; private Scroller scroller; private int mTouchSlop = 0; private int mLastY; private int mLastInterceptY; private int mHeaderHeight; public final static int SCREEN_HEADER = 11; public final static int SCREEN_FOOTER = 12; private int screen = SCREEN_HEADER; @SuppressLint("NewApi") public TBLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public TBLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public TBLayout(Context context) { super(context); init(); } private void init() { scroller = new Scroller(getContext()); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); if (hasWindowFocus && mHeader == null && mFooter == null) { initData(); } } private void initData() { mHeader = findViewById(R.id.header); mFooter = findViewById(R.id.footer); ViewGroup.LayoutParams lps = mFooter.getLayoutParams(); mHeaderHeight = mHeader.getMeasuredHeight(); lps.height = mHeaderHeight; mFooter.setLayoutParams(lps); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean result = false; final int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastInterceptY = mLastY = y; break; case MotionEvent.ACTION_MOVE: int dy = y - mLastInterceptY; if (dy > mTouchSlop && screen == SCREEN_FOOTER) {// pull down result = (pullListener != null && pullListener .footerHeadReached(ev)); } else if (dy < -mTouchSlop && screen == SCREEN_HEADER) { // pull up result = (pullListener != null && pullListener .headerFootReached(ev)); } break; case MotionEvent.ACTION_UP: mLastInterceptY = 0; break; } return result; } @Override public boolean onTouchEvent(MotionEvent event) { final int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: int dy = y - mLastY; switch (screen) { case SCREEN_HEADER: int sy = -dy; if (sy < 0) { sy = 0; } else if (sy > getHeight()) { sy = getHeight(); } scrollTo(0, sy); break; case SCREEN_FOOTER: if (dy > 0) { scrollTo(0, mHeaderHeight - dy); } else { // dy < 0 } break; } break; case MotionEvent.ACTION_UP: int t = 0; switch (screen) { case SCREEN_HEADER: t = mHeaderHeight / 4; break; case SCREEN_FOOTER: t = mHeaderHeight * 3 / 4; break; } int sy = getScrollY(); if (sy > t) { // scroll to footer scroller.startScroll(0, sy, 0, mHeaderHeight - sy, 150); screen = SCREEN_FOOTER; if (ctListener != null) { ctListener.onPageChanged(SCREEN_FOOTER); } invalidate(); } else { // scroll to header scroller.startScroll(0, sy, 0, -sy, 150); screen = SCREEN_HEADER; if (ctListener != null) { ctListener.onPageChanged(SCREEN_HEADER); } invalidate(); } mLastY = 0; break; } return true; } @Override public void computeScroll() { if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } } public interface OnPullListener { // 到达Header(第一页)的底部 public boolean headerFootReached(MotionEvent event); // 到达Footer(第二页)的顶部 public boolean footerHeadReached(MotionEvent event); } public interface OnPageChangedListener { // 页面改变事件 public void onPageChanged(int stub); } }
Activity_ScrollView中
activity_scrollview.xml中package com.taobao.detailview; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import com.taobao.detailview.TBLayout.OnPageChangedListener; import com.taobao.detailview.TBLayout.OnPullListener; /** * Header's root is ScrollView , Footer's root is ScrollView * * @author zy * */ @SuppressWarnings("unused") public class Activity_ScrollView extends Activity { // 滑动翻页的外层自定义控件 private TBLayout tblayout; // 第一页的ScrollView private ScrollView header; // 和第二页的ScrollView private ScrollView footer; // 第一页ScrollView的内容 private LinearLayout mHeaderContent; // 第二页ScrollView的内容 private LinearLayout mFooterContent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_scrollview); tblayout = (TBLayout) findViewById(R.id.tblayout); header = (ScrollView) findViewById(R.id.header); footer = (ScrollView) findViewById(R.id.footer); mHeaderContent = (LinearLayout) header.getChildAt(0); mFooterContent = (LinearLayout) footer.getChildAt(0); tblayout.setOnPullListener(new OnPullListener() { @Override public boolean headerFootReached(MotionEvent event) { if (header.getScrollY() + header.getHeight() >= mHeaderContent .getHeight()) { return true; } return false; } @Override public boolean footerHeadReached(MotionEvent event) { if (footer.getScrollY() == 0) { return true; } return false; } }); // 翻页 tblayout.setOnContentChangeListener(new OnPageChangedListener() { @Override public void onPageChanged(int stub) { switch (stub) { case TBLayout.SCREEN_HEADER: Log.d("tag", "SCREEN_HEADER"); Toast.makeText(Activity_ScrollView.this,"第一页",Toast.LENGTH_SHORT).show(); break; case TBLayout.SCREEN_FOOTER: Log.d("tag", "SCREEN_FOOTER"); Toast.makeText(Activity_ScrollView.this,"第2页",Toast.LENGTH_SHORT).show(); break; } } }); } }
page1_scrollview.xml<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <com.taobao.detailview.TBLayout android:id="@+id/tblayout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#646464" android:orientation="vertical" > <ScrollView android:id="@id/header" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#449cfd" > <include layout="@layout/page1_scrollview" /> </ScrollView> <ScrollView android:id="@id/footer" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#f97171" > <include layout="@layout/page2_scrollview" /> </ScrollView> </com.taobao.detailview.TBLayout> </LinearLayout>
page2_scrollview.xml<?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="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/tvPage1" android:layout_width="match_parent" android:layout_height="200.0dip" android:gravity="center" android:text="我是第一页" android:textColor="#ff0000" android:textSize="18sp" /> <TextView android:layout_width="match_parent" android:layout_height="200.0dip" android:gravity="center" android:text="我是第一页" android:textColor="#ff0000" android:textSize="18sp" /> <TextView android:layout_width="match_parent" android:layout_height="200.0dip" android:gravity="center" android:text="我是第一页" android:textColor="#ff0000" android:textSize="18sp" /> <TextView android:layout_width="match_parent" android:layout_height="200.0dip" android:gravity="center" android:text="我是第一页" android:textColor="#ff0000" android:textSize="18sp" /> <TextView android:layout_width="match_parent" android:layout_height="200.0dip" android:gravity="center" android:text="我是第一页" android:textColor="#ff0000" android:textSize="18sp" /> <TextView android:layout_width="match_parent" android:layout_height="200.0dip" android:gravity="center" android:text="我是第一页" android:textColor="#ff0000" android:textSize="18sp" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="10.0dip" android:text="--继续拖动,查看图文详情--" android:textSize="15sp" /> </LinearLayout>
id.xml<?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="wrap_content" android:orientation="vertical" > <!--滑动后下面的部分,包含选项卡--> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!--头部--> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal" android:background="@android:color/white" > <!--详情页--> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" > <!--3个选项卡--> <!--选项卡1--> <LinearLayout android:id="@+id/llTuWen" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <TextView android:id="@+id/tvTuWen" android:layout_width="wrap_content" android:layout_height="48dp" android:text="图文详情" android:gravity="center" android:layout_gravity="center" android:textSize="14sp" /> <TextView android:id="@+id/tvTag1" android:layout_width="72dp" android:layout_height="2dp" android:gravity="center" android:layout_gravity="center" /> </LinearLayout> <LinearLayout android:id="@+id/llTaoCan" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <TextView android:layout_width="wrap_content" android:layout_height="48dp" android:text="套餐说明" android:gravity="center" android:layout_gravity="center" android:textSize="14sp" android:textColor="#666666" /> <TextView android:id="@+id/tvTag2_1" android:layout_width="72dp" android:layout_height="2dp" android:gravity="center" android:layout_gravity="center" android:visibility="gone" /> </LinearLayout> <LinearLayout android:id="@+id/llParameter" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <TextView android:id="@+id/tvCanShu" android:layout_width="wrap_content" android:layout_height="48dp" android:text="规格参数" android:gravity="center" android:layout_gravity="center" android:textSize="14sp" android:textColor="#666666" /> <TextView android:id="@+id/tvTag2" android:layout_width="72dp" android:layout_height="2dp" android:gravity="center" android:layout_gravity="center" android:visibility="gone" /> </LinearLayout> <LinearLayout android:id="@+id/llSellAfter" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <TextView android:id="@+id/tvShouHou" android:layout_width="wrap_content" android:layout_height="48dp" android:text="包装售后" android:gravity="center" android:layout_gravity="center" android:textSize="14sp" android:textColor="#666666" /> <TextView android:id="@+id/tvTag3" android:layout_width="72dp" android:layout_height="2dp" android:gravity="center" android:layout_gravity="center" android:visibility="gone" /> </LinearLayout> </LinearLayout> </LinearLayout> <!--下面部分,装入不同的布局,在外面包一层,滑动布局--> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/llContainerfragment" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout> </ScrollView> </RelativeLayout> </LinearLayout>
源码下载:<?xml version="1.0" encoding="utf-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android"> <item name="header" type="id">12</item> <item name="footer" type="id">34</item> </resources>
http://download.youkuaiyun.com/detail/zhaihaohao1/9815988