仿淘寶商品詳情頁中(繼續拖動到圖文詳情)
阿新 • • 發佈:2019-01-30
核心view 有2個
- 一個是自定義的ViewGroup
- 一個是自定義的ScrollView
首先是自定義的ScrollView
public class MyScrollView extends ScrollView {
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setScrollListener(ScrollListener scrollListener) {
this.mScrollListener = scrollListener;
}
private static String TAG=MyScrollView.class.getName();
private ScrollListener mScrollListener;
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_MOVE:
if(mScrollListener!=null){
//得到第一個,也就是子view中]所有的view的 總高點,
int contentHeight=getChildAt(0 ).getHeight();
Log.d("---->>>>>" , "contentHeight"+contentHeight);
//得到狀態列到螢幕底部的距離,
int scrollHeight = getHeight();
Log.d("---->>>>>" , "scrollHeight"+scrollHeight);
//得到ScrollView中滾動的最高位置
int scrollY = getScrollY();
Log.d("---->>>>>" , "getScrollY()"+scrollY);
mScrollListener.onScroll(scrollY);
//判斷最高位置+ 狀態列到底部的位置 > 總位置 , 那麼就執行到下一個ScrollView的檢視,否則還是笨檢視
if(scrollY+scrollHeight>=contentHeight||contentHeight<=scrollHeight){
mScrollListener.onScrollToBottom();
}else {
mScrollListener.notBottom();
}
if(scrollY==0){
mScrollListener.onScrollToTop();
}
}
break;
}
boolean result=super.onTouchEvent(ev);
//表示子view不能有自己的處理事件
requestDisallowInterceptTouchEvent(false);
return result;
}
//滑動監聽事件
public interface ScrollListener{
void onScrollToBottom();//跳到下一頁
void onScrollToTop();//跳到上一頁
//根據當前ScrollY是0還是最大來決定跳轉還是停留
void onScroll(int scrollY);
void notBottom();//不跳轉
}
}
- 然後就是主要的自定義GroupView
public class MyTwoViewGroup extends ViewGroup {
MyScrollView topScrollView, bottomScrollView;
VelocityTracker velocityTracker = VelocityTracker.obtain();
Scroller scroller = new Scroller(getContext());
int currPosition = 0;//0表示第一頁,1表示第二頁
int position1Y;//彈性滑動的Y軸方向
int lastY;//記錄移動完後最後的座標
public int scaledTouchSlop;//最小滑動距離
int speed = 200;//滑動速度
boolean isIntercept;//父類是否攔截
public boolean bottomScrollVIewIsInTop = false;//true表示第二頁已經到最頂部了
public boolean topScrollViewIsBottom = false;//true表示第一頁已經滾動到最底部了!,
public MyTwoViewGroup(Context context) {
super(context);
init();
}
public MyTwoViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyTwoViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
post(new Runnable() {
@Override
public void run() {
topScrollView = (MyScrollView) getChildAt(0);
bottomScrollView = (MyScrollView) getChildAt(1);
topScrollView.setScrollListener(new MyScrollView.ScrollListener() {
@Override
public void onScrollToBottom() {
topScrollViewIsBottom = true;
}
@Override
public void onScrollToTop() {
}
@Override
public void onScroll(int scrollY) {
}
@Override
public void notBottom() {
topScrollViewIsBottom = false;//底部不顯示
}
});
bottomScrollView.setScrollListener(new MyScrollView.ScrollListener() {
@Override
public void onScrollToBottom() {
}
@Override
public void onScrollToTop() {
}
@Override
public void onScroll(int scrollY) {
if (scrollY == 0) {
bottomScrollVIewIsInTop = true;
} else {
bottomScrollVIewIsInTop = false;
}
}
@Override
public void notBottom() {
}
});
position1Y = topScrollView.getBottom();
scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//防止子View禁止父view攔截事件
this.requestDisallowInterceptTouchEvent(false);
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
//判斷是否已經滾動到了底部
if (topScrollViewIsBottom) {
int dy = lastY - y;
//判斷是否是向上滑動和是否在第一屏
if (dy > 0 && currPosition == 0) {
//偏離量是否 大於 滑動速度
if (dy >= scaledTouchSlop) {
isIntercept = true;//攔截事件
lastY=y;
}
}
}
if (bottomScrollVIewIsInTop) {
int dy = lastY - y;
//判斷是否是向下滑動和是否在第二屏
if (dy < 0 && currPosition == 1) {
if (Math.abs(dy) >= scaledTouchSlop) {
isIntercept = true;
}
}
}
break;
}
return isIntercept;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getY();
//新增一個使用者的運動跟蹤
velocityTracker.addMovement(event);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
int dy = lastY - y;
if (getScrollY() + dy < 0) {
dy = getScrollY() + dy + Math.abs(getScrollY() + dy);
}
if (getScrollY() + dy + getHeight() > bottomScrollView.getBottom()) {
dy = dy - (getScrollY() + dy - (bottomScrollView.getBottom() - getHeight()));
}
scrollBy(0, dy);
break;
case MotionEvent.ACTION_UP:
isIntercept = false;
//計算當前速度的基礎上,收集點
velocityTracker.computeCurrentVelocity(1000);
//檢索最後計算Y速度。
float yVelocity = velocityTracker.getYVelocity();
if (currPosition == 0) {
if (yVelocity < 0 && yVelocity < -speed) {
smoothScroll(position1Y);
currPosition = 1;
} else {
smoothScroll(0);
}
} else {
if (yVelocity > 0 && yVelocity > speed) {
smoothScroll(0);
currPosition = 0;
} else {
smoothScroll(position1Y);
}
}
break;
}
lastY = y;
return true;
}
//子view的寬高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
}
//第一個子view自身高度, 第二個子view的 頂部 是從第一個子view的總高度開始的
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int childTop = t;
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
child.layout(l, childTop, r, childTop + child.getMeasuredHeight());
childTop += child.getMeasuredHeight();
}
}
//通過Scroller實現彈性滑動
private void smoothScroll(int tartY) {
int dy = tartY - getScrollY();
scroller.startScroll(getScrollX(), getScrollY(), 0, dy);
invalidate();//重繪
}
//onDraw中執行這個
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
}
- 然後就是佈局檔案的使用
- 主要就是2個自定義的ScrollView中放置的子view
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.xingao.com.recycleviewtest.DetailActivity">
<com.xingao.com.recycleviewtest.ui.MyTwoViewGroup
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.xingao.com.recycleviewtest.ui.MyScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:scaleType="fitXY"
android:src="@drawable/a1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:text="這裡是標題"
android:textSize="18dp"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_marginTop="10dp"
android:text="子標題"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:textSize="18dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="bottom"
android:layout_width="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:height="50dp"
android:background="#b11"
android:gravity="center"
android:text="繼續拖動檢視圖文詳情"
android:textColor="#000" />
</LinearLayout>
</LinearLayout>
</com.xingao.com.recycleviewtest.ui.MyScrollView>
<com.xingao.com.recycleviewtest.ui.MyScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="fitXY"
android:src="@drawable/a1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/a3" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/a3" />
</LinearLayout>
</com.xingao.com.recycleviewtest.ui.MyScrollView>
</com.xingao.com.recycleviewtest.ui.MyTwoViewGroup>
</RelativeLayout>
-
-