300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > android向上拖动查看图文详情控件

android向上拖动查看图文详情控件

时间:2023-12-11 22:47:28

相关推荐

android向上拖动查看图文详情控件

摘自:/qifengdeqingchen/article/details/51659735

一、淘宝商品详情页效果

先看一下淘宝详情页的效果

我们的效果

二、实现思路

使用两个scrollView,两个scrollView 竖直排列,通过自定义viewGroup来控制两个scrollView的竖直排列,以及滑动事件的处理。如下图

三、具体实现

1、继承viewGroup自定义布局View 重写onMeasure()和onLayout方法,在onLayout方法中完成对两个子ScrollView的竖直排列布局,代码如下: 布局文件:

[java]view plain copy print ? <RelativeLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.baoyunlong.view.pulluptoloadmore.MainActivity"><com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMoreandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><com.baoyunlong.view.pulluptoloadmore.MyScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:fillViewport="true"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:scaleType="fitXY"android:src="@drawable/a1"android:layout_width="match_parent"android:layout_height="180dp"/><TextViewandroid: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"/><TextViewandroid: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"/>..............<LinearLayoutandroid:layout_height="0dp"android:layout_weight="1"android:gravity="bottom"android:layout_width="match_parent"><TextViewandroid: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.baoyunlong.view.pulluptoloadmore.MyScrollView><com.baoyunlong.view.pulluptoloadmore.MyScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:fillViewport="true"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/a1"/><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/a3"/>.........</LinearLayout></com.baoyunlong.view.pulluptoloadmore.MyScrollView></com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore></RelativeLayout>

<RelativeLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.baoyunlong.view.pulluptoloadmore.MainActivity"><com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMoreandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><com.baoyunlong.view.pulluptoloadmore.MyScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:fillViewport="true"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:scaleType="fitXY"android:src="@drawable/a1"android:layout_width="match_parent"android:layout_height="180dp" /><TextViewandroid: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" /><TextViewandroid: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" />..............<LinearLayoutandroid:layout_height="0dp"android:layout_weight="1"android:gravity="bottom"android:layout_width="match_parent"><TextViewandroid: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.baoyunlong.view.pulluptoloadmore.MyScrollView><com.baoyunlong.view.pulluptoloadmore.MyScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:fillViewport="true"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/a1" /><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/a3" />.........</LinearLayout></com.baoyunlong.view.pulluptoloadmore.MyScrollView></com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore></RelativeLayout>

代码:[java]view plain copy print ? publicclassPullUpToLoadMoreextendsViewGroup{publicPullUpToLoadMore(Contextcontext){super(context);}publicPullUpToLoadMore(Contextcontext,AttributeSetattrs){super(context,attrs);}publicPullUpToLoadMore(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);}@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){super.onMeasure(widthMeasureSpec,heightMeasureSpec);measureChildren(widthMeasureSpec,heightMeasureSpec);}@OverrideprotectedvoidonLayout(booleanchanged,intl,intt,intr,intb){intchildCount=getChildCount();intchildTop=t;for(inti=0;i<childCount;i++){Viewchild=getChildAt(i);child.layout(l,childTop,r,childTop+child.getMeasuredHeight());childTop+=child.getMeasuredHeight();}}}

public class PullUpToLoadMore extends ViewGroup {public PullUpToLoadMore(Context context) {super(context);}public PullUpToLoadMore(Context context, AttributeSet attrs) {super(context, attrs);}public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);measureChildren(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected 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();}}}

2、处理滑动事件 规则如下 : (1)、当处于第一屏时 第一个ScrollView已经滑动到底部并且滑动方向是往上滑动,这个时候滑动事件应该交给父view处理也就是拦截事件让onInterceptTouchEvent返回true.然后父view通过scrollBy()方法滚动,显示出第二个scrollView。(2)、当处于第二屏时 第二个ScrollView已经滑动到顶部并且滑动方向是往下滑动,这个时候滑动事件交给父view处理,根据滑动事件显示出第一个ScrollView。(3)、当手指离开屏幕时,根据滑动速度来决定是回弹到第一个ScrollView还是第二个ScrollView,通过VelocityTracker来获取滑动速度。 3、一些细节的处理 (1)、如果仔细看观察淘宝的实现效果你会发现,当你滑动到刚刚看到 “继续拖动,查看图文详情”的时候,手指抬起,然后再按下重新向上拖动你会发现,第二页并不会划出来,而是停留在了“继续拖动,查看图文详情”的底部,京东的效果也是一样。这样用户体验不太好,我们来优化一下。其实通过查看ScrollView的源码可以看出来,这是因为ScrollView类的onTouchEvent方法的默认实现,调用了parent.requestDisallowInterceptTouchEvent(true)方法 阻止了我们拦截事件,导致我们父view的onInterceptTouchEvent方法无法执行,也就拦截不到事件,拦截不到事件我们的onTouchEvent就无法执行,onTouchEvent无法执行,我们写在onTouchEvent里面的滚动逻辑就执行不到了,导致了上面我们看到的划不动的效果。解决方法就是,我们需要重写dispatchTouchEvent()方法,防止子view干扰我们,这样我们滑动的时候就可以一气呵成了。代码如下:[java]view plain copy print ? @OverridepublicbooleandispatchTouchEvent(MotionEventev){//防止子View禁止父view拦截事件this.requestDisallowInterceptTouchEvent(false);returnsuper.dispatchTouchEvent(ev);}

@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {//防止子View禁止父view拦截事件this.requestDisallowInterceptTouchEvent(false);return super.dispatchTouchEvent(ev);}

(2)、监听ScrollView滑动事件的问题

ScrollView没有提供滚动事件的监听方法,也就没法判断是否滚动到了顶部,或者底部,这里我们继承ScrollView 自己实现滚动事件监听。[java]view plain copy print ? /***Createdbybaoyunlongon16/6/8.*/publicclassMyScrollViewextendsScrollView{privatestaticStringTAG=MyScrollView.class.getName();publicvoidsetScrollListener(ScrollListenerscrollListener){this.mScrollListener=scrollListener;}privateScrollListenermScrollListener;publicMyScrollView(Contextcontext){super(context);}publicMyScrollView(Contextcontext,AttributeSetattrs){super(context,attrs);}publicMyScrollView(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);}@OverridepublicbooleanonTouchEvent(MotionEventev){switch(ev.getAction()){caseMotionEvent.ACTION_MOVE:if(mScrollListener!=null){intcontentHeight=getChildAt(0).getHeight();intscrollHeight=getHeight();intscrollY=getScrollY();mScrollListener.onScroll(scrollY);if(scrollY+scrollHeight>=contentHeight||contentHeight<=scrollHeight){mScrollListener.onScrollToBottom();}else{mScrollListener.notBottom();}if(scrollY==0){mScrollListener.onScrollToTop();}}break;}booleanresult=super.onTouchEvent(ev);requestDisallowInterceptTouchEvent(false);returnresult;}publicinterfaceScrollListener{voidonScrollToBottom();voidonScrollToTop();voidonScroll(intscrollY);voidnotBottom();}

/*** Created by baoyunlong on 16/6/8.*/public class MyScrollView extends ScrollView {private static String TAG=MyScrollView.class.getName();public void setScrollListener(ScrollListener scrollListener) {this.mScrollListener = scrollListener;}private ScrollListener mScrollListener;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);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()){case MotionEvent.ACTION_MOVE:if(mScrollListener!=null){int contentHeight=getChildAt(0).getHeight();int scrollHeight=getHeight();int scrollY=getScrollY();mScrollListener.onScroll(scrollY);if(scrollY+scrollHeight>=contentHeight||contentHeight<=scrollHeight){mScrollListener.onScrollToBottom();}else {mScrollListener.notBottom();}if(scrollY==0){mScrollListener.onScrollToTop();}}break;}boolean result=super.onTouchEvent(ev);requestDisallowInterceptTouchEvent(false);return result;}public interface ScrollListener{void onScrollToBottom();void onScrollToTop();void onScroll(int scrollY);void notBottom();}

4、完整代码如下[java]view plain copy print ? /***Createdbybaoyunlongon16/6/8.*/publicclassPullUpToLoadMoreextendsViewGroup{publicstaticStringTAG=PullUpToLoadMore.class.getName();MyScrollViewtopScrollView,bottomScrollView;VelocityTrackervelocityTracker=VelocityTracker.obtain();Scrollerscroller=newScroller(getContext());intcurrPosition=0;intposition1Y;intlastY;publicintscaledTouchSlop;//最小滑动距离intspeed=200;booleanisIntercept;publicbooleanbottomScrollVIewIsInTop=false;publicbooleantopScrollViewIsBottom=false;publicPullUpToLoadMore(Contextcontext){super(context);init();}publicPullUpToLoadMore(Contextcontext,AttributeSetattrs){super(context,attrs);init();}publicPullUpToLoadMore(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);init();}privatevoidinit(){post(newRunnable(){@Overridepublicvoidrun(){topScrollView=(MyScrollView)getChildAt(0);bottomScrollView=(MyScrollView)getChildAt(1);topScrollView.setScrollListener(newMyScrollView.ScrollListener(){@OverridepublicvoidonScrollToBottom(){topScrollViewIsBottom=true;}@OverridepublicvoidonScrollToTop(){}@OverridepublicvoidonScroll(intscrollY){}@OverridepublicvoidnotBottom(){topScrollViewIsBottom=false;}});bottomScrollView.setScrollListener(newMyScrollView.ScrollListener(){@OverridepublicvoidonScrollToBottom(){}@OverridepublicvoidonScrollToTop(){}@OverridepublicvoidonScroll(intscrollY){if(scrollY==0){bottomScrollVIewIsInTop=true;}else{bottomScrollVIewIsInTop=false;}}@OverridepublicvoidnotBottom(){}});position1Y=topScrollView.getBottom();scaledTouchSlop=ViewConfiguration.get(getContext()).getScaledTouchSlop();}});}@OverridepublicbooleandispatchTouchEvent(MotionEventev){//防止子View禁止父view拦截事件this.requestDisallowInterceptTouchEvent(false);returnsuper.dispatchTouchEvent(ev);}@OverridepublicbooleanonInterceptTouchEvent(MotionEventev){inty=(int)ev.getY();switch(ev.getAction()){caseMotionEvent.ACTION_DOWN:lastY=y;break;caseMotionEvent.ACTION_MOVE://判断是否已经滚动到了底部if(topScrollViewIsBottom){intdy=lastY-y;//判断是否是向上滑动和是否在第一屏if(dy>0&&currPosition==0){if(dy>=scaledTouchSlop){isIntercept=true;//拦截事件lastY=y;}}}if(bottomScrollVIewIsInTop){intdy=lastY-y;//判断是否是向下滑动和是否在第二屏if(dy<0&&currPosition==1){if(Math.abs(dy)>=scaledTouchSlop){isIntercept=true;}}}break;}returnisIntercept;}@OverridepublicbooleanonTouchEvent(MotionEventevent){inty=(int)event.getY();velocityTracker.addMovement(event);switch(event.getAction()){caseMotionEvent.ACTION_MOVE:intdy=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;caseMotionEvent.ACTION_UP:isIntercept=false;puteCurrentVelocity(1000);floatyVelocity=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;returntrue;}@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){super.onMeasure(widthMeasureSpec,heightMeasureSpec);measureChildren(widthMeasureSpec,heightMeasureSpec);}@OverrideprotectedvoidonLayout(booleanchanged,intl,intt,intr,intb){intchildCount=getChildCount();intchildTop=t;for(inti=0;i<childCount;i++){Viewchild=getChildAt(i);child.layout(l,childTop,r,childTop+child.getMeasuredHeight());childTop+=child.getMeasuredHeight();}}//通过Scroller实现弹性滑动privatevoidsmoothScroll(inttartY){intdy=tartY-getScrollY();scroller.startScroll(getScrollX(),getScrollY(),0,dy);invalidate();}@OverridepublicvoidcomputeScroll(){if(puteScrollOffset()){scrollTo(scroller.getCurrX(),scroller.getCurrY());postInvalidate();}}}

/*** Created by baoyunlong on 16/6/8.*/public class PullUpToLoadMore extends ViewGroup {public static String TAG = PullUpToLoadMore.class.getName();MyScrollView topScrollView, bottomScrollView;VelocityTracker velocityTracker = VelocityTracker.obtain();Scroller scroller = new Scroller(getContext());int currPosition = 0;int position1Y;int lastY;public int scaledTouchSlop;//最小滑动距离int speed = 200;boolean isIntercept;public boolean bottomScrollVIewIsInTop = false;public boolean topScrollViewIsBottom = false;public PullUpToLoadMore(Context context) {super(context);init();}public PullUpToLoadMore(Context context, AttributeSet attrs) {super(context, attrs);init();}public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {post(new Runnable() {@Overridepublic void run() {topScrollView = (MyScrollView) getChildAt(0);bottomScrollView = (MyScrollView) getChildAt(1);topScrollView.setScrollListener(new MyScrollView.ScrollListener() {@Overridepublic void onScrollToBottom() {topScrollViewIsBottom = true;}@Overridepublic void onScrollToTop() {}@Overridepublic void onScroll(int scrollY) {}@Overridepublic void notBottom() {topScrollViewIsBottom = false;}});bottomScrollView.setScrollListener(new MyScrollView.ScrollListener() {@Overridepublic void onScrollToBottom() {}@Overridepublic void onScrollToTop() {}@Overridepublic void onScroll(int scrollY) {if (scrollY == 0) {bottomScrollVIewIsInTop = true;} else {bottomScrollVIewIsInTop = false;}}@Overridepublic void notBottom() {}});position1Y = topScrollView.getBottom();scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();}});}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {//防止子View禁止父view拦截事件this.requestDisallowInterceptTouchEvent(false);return super.dispatchTouchEvent(ev);}@Overridepublic 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;}@Overridepublic 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;puteCurrentVelocity(1000);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;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);measureChildren(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected 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();}@Overridepublic void computeScroll() {if (puteScrollOffset()) {scrollTo(scroller.getCurrX(), scroller.getCurrY());postInvalidate();}}}

四、源码

github地址

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。