因项目需求要实现类似于百度地图上下拖动的效果,特此分享,百度地图效果:

地图显示为一个Activity,View可以跟随手指的滑动而移动,手指松开时自动滑动到屏幕的底部或者顶部。
直接上代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_second"android:layout_width="match_parent"android:layout_height="match_parent"><com.test.updown.view.UpAndDownView
        android:id="@+id/up_down_view"android:visibility="gone"android:layout_alignParentBottom="true"android:layout_width="match_parent"android:layout_height="match_parent"></com.test.updown.view.UpAndDownView></RelativeLayout>

布局文件,因为需求是View在地图的底部,所以自定义UpAndDownView放在了parent的bottom,这里默认隐藏。
下面是自定义UpAndDownView代码

public class UpAndDownView extends CustomUpAndDownLayout {private Context mContext;public UpAndDownView(Context context) {super(context);initView(context);}public UpAndDownView(Context context, AttributeSet attrs) {super(context, attrs);initView(context);}public void initView(final Context mContext) {this.mContext = mContext;View view = LayoutInflater.from(mContext).inflate(R.layout.up_down_layout, null, false);addView(view);InnerScrollView innerScrollView = (InnerScrollView) view.findViewById(R.id.scrollView);if (innerScrollView != null) {innerScrollView.parentView = UpAndDownView.this;}view.findViewById(R.id.textview).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(mContext, "Click the TextView", 0).show();}});}public void setUpDownListener(UpAndDownListener listener) {setListener(listener);}public void setIsSlide(boolean isSlide) {isSlide(isSlide);}public boolean isSlide() {return isCanSlide();}
}

自定义View的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:background="#f00"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayout
        android:id="@+id/title"android:layout_width="match_parent"android:background="#ff0"android:layout_height="60dp"><TextView
            android:layout_centerInParent="true"android:text="这是标题"android:textSize="20dp"android:layout_width="wrap_content"android:layout_height="wrap_content"/></RelativeLayout><com.test.updown.view.InnerScrollView
        android:fillViewport="true"android:id="@+id/scrollView"android:layout_below="@id/title"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayout
            android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><TextView
                android:id="@+id/textview"android:gravity="center"android:text="这是内容"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout></com.test.updown.view.InnerScrollView>
</RelativeLayout>

代码依旧很简单,自定义View继承了一个自定义的RelativeLayout,具体的滑动由自定义的RelativeLayout来实现,布局了自定义的ScrollView用来解决事件冲突,下面是核心代码

   @Overridepublic boolean onTouch(View view, MotionEvent event) {if (!isSlide) {return false;}createVelocityTracker(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 手指按下时,记录按下时的坐标xDown = event.getRawX();yDown = event.getRawY();downY = event.getRawY();// 将滑动状态初始化为DO_NOTHINGslideState = DO_NOTHING;// currTime = System.currentTimeMillis();break;case MotionEvent.ACTION_MOVE:if (xDown == 0 && yDown == 0) {xDown = event.getRawX();yDown = event.getRawY();downY = event.getRawY();} else {xMove = event.getRawX();yMove = event.getRawY();int moveDistanceX = (int) (xMove - xDown);int moveDistanceY = (int) (yMove - yDown);// 当默认是要显示全屏时,这个地方获取到的高度是-1(原因不清楚)if (contentLayoutParams.height == -1) {contentLayoutParams.height = showMaxHeight;}int tempheight = contentLayoutParams.height;// 得当前Layout距离顶部的距离// 当布局已经到达底部或者已经到达顶部时,移动无效if ((tempheight >= showMaxHeight && moveDistanceY < 0)|| (tempheight <= Utils.dp2Px(mContext,defaultShowHeight) && moveDistanceY > 0)) {break;}// 检查当前的滑动状态checkSlideState(moveDistanceX, moveDistanceY);switch (slideState) {case HIDING:contentLayoutParams.height = showMaxHeight - moveDistanceY;setLayoutParams(contentLayoutParams);break;case HIDEING_2:case SHOWING:int height = contentLayoutParams.height;contentLayoutParams.height = height - moveDistanceY;setLayoutParams(contentLayoutParams);yDown = event.getRawY();break;default:break;}}break;case MotionEvent.ACTION_UP:yUp = event.getRawY();if (isSliding) {// 手指抬起时,进行判断当前手势的意图,这里可根据当前的位置判断显示还是隐藏switch (slideState) {case HIDING:case HIDEING_2:if (shouldScrollToUpMenu()) {scrollToUpMenu();} else {scrollToContentFromUpMenu();}break;case SHOWING:if (shouldScrollToContentFromUpMenu()) {scrollToContentFromUpMenu();} else {scrollToUpMenu();}break;default:break;}}recycleVelocityTracker();break;}return true;}

基本流程是: 在onTouch事件的Action_Move事件中随着手指的移动改变Layout的高度,在Action_Up事件中根据抬起的位置判断View是全屏显示还是在底部显示。
注意:因为是在onTouch方法做了一系列滑动监听工作,所以当View中放置了其他控件的时候onTouch事件会监听不到导致滑动的失效,下面是解决滑动冲突:

 @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:isScrolling = false;xDown = 0;yDown = 0;xDown1 = ev.getX();yDown1 = ev.getY();bScrollUpDown = false;break;case MotionEvent.ACTION_MOVE:float moveX = ev.getX();float moveY = ev.getY();float disX = moveX - xDown1;float disY = moveY - yDown1;if (Math.abs((int) disY) > Utils.dp2Px(mContext, moveMinValue)) {bScrollUpDown = Math.abs(disX * 1000) < Math.abs(disY * 1000);}return bScrollUpDown;case MotionEvent.ACTION_UP:break;}boolean bRet = super.onInterceptTouchEvent(ev);return bRet;}

InnserScrollView的代码

public class InnerScrollView extends ScrollView {/***/private int moveMinValue = 20;public RelativeLayout parentView;public InnerScrollView(Context context, AttributeSet attrs) {super(context, attrs);}private int lastScrollDelta = 0;public void resume() {overScrollBy(0, -lastScrollDelta, 0, getScrollY(), 0, getScrollRange(), 0, 0, true);lastScrollDelta = 0;}int mTop = 10;/*** 将targetView滚到最顶端*/public void scrollTo(View targetView) {int oldScrollY = getScrollY();int top = targetView.getTop() - mTop;int delatY = top - oldScrollY;lastScrollDelta = delatY;overScrollBy(0, delatY, 0, getScrollY(), 0, getScrollRange(), 0, 0, true);}private int getScrollRange() {int scrollRange = 0;if (getChildCount() > 0) {View child = getChildAt(0);scrollRange = Math.max(0, child.getHeight() - (getHeight()));}return scrollRange;}int currentY;@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (parentView == null) {return super.onInterceptTouchEvent(ev);} else {if (ev.getAction() == MotionEvent.ACTION_DOWN) {// 将父scrollview的滚动事件拦截currentY = (int) ev.getY();setParentScrollAble(false);
//                Debuglog.i("innerScroll", "ACTION_DOWN");return super.onInterceptTouchEvent(ev);} else if (ev.getAction() == MotionEvent.ACTION_UP) {// 把滚动事件恢复给父ScrollviewsetParentScrollAble(true);
//                Debuglog.i("innerScroll", "ACTION_UP");} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {float moveY = ev.getY();float dixY = moveY - currentY;if (Math.abs(dixY) > Utils.dp2Px(getContext(), moveMinValue)) {
//                     Debuglog.i("innerScroll", "ACTION_MOVE");return true;}//返回true把事件交给onTounch去处理//return true;}}return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {View child = getChildAt(0);try {if (parentView != null) {if (ev.getAction() == MotionEvent.ACTION_MOVE) {int height = child.getMeasuredHeight();height = height - getMeasuredHeight();// System.out.println("height=" + height);int scrollY = getScrollY();// System.out.println("scrollY" + scrollY);int y = (int) ev.getY();// 手指向下滑动if (currentY < y) {if (scrollY <= 0) {// 如果向下滑动到头,就把滚动交给父ScrollviewsetParentScrollAble(true);return false;} else {setParentScrollAble(false);}} else if (currentY > y) {if (scrollY >= height) {// 如果向上滑动到头,就把滚动交给父ScrollviewsetParentScrollAble(true);return false;} else {setParentScrollAble(false);}}currentY = y;}}return super.onTouchEvent(ev);} catch (IllegalArgumentException e) {// TODO: handle exception}return false;}/*** 是否把滚动事件交给父scrollview** @param flag*/private void setParentScrollAble(boolean flag) {parentView.requestDisallowInterceptTouchEvent(!flag);}@Overrideprotected void onScrollChanged(int l, int t, int oldl, int oldt) {if(listener!=null){listener.onScrollChanged(l, t, oldl, oldt);}if(getScrollY() + getHeight() ==  computeVerticalScrollRange()){if (listener != null) {int scrollY = getScrollY();View childView=getChildAt(0);if (scrollY==childView.getHeight()-getHeight()){listener.scrollBottom();}}}}ScrollViewListener listener;public  void setScrollViewListener(ScrollViewListener listener){this.listener=listener;}public interface ScrollViewListener{public void scrollBottom();void onScrollChanged(int l, int t, int oldl, int oldt);}@Overrideprotected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {return 0;}
}

下面是代码运行效果:

这里只是简单的一个Demo实现,基本上可以满足大部分的需求,由于CSDN对图片大小有限制,所以将项目截图放到了GitHub上,有类似需求可以作为参考,有不足之处欢迎大家来指正。
https://github.com/dingys/UpDownDemo

防百度地图上下拖动View相关推荐

  1. android百度地图定位跳转中心点,百度地图,拖动地图,定位marker固定在屏幕中心位置...

    以下为百度地图相关效果图: 注:该例子主要思路是将覆盖物(marker)通过css定位上去的,但是存在一个问题,当浏览器窗口宽度改变时,覆盖物会自动定位到地图中心位置,但是地图可能不会. map ht ...

  2. android百度地图拖拽地图定位,百度地图,拖动地图,定位marker固定在屏幕中心位置...

    以下为百度地图相关效果图: 注:该例子主要思路是将覆盖物(marker)通过css定位上去的,但是存在一个问题,当浏览器窗口宽度改变时,覆盖物会自动定位到地图中心位置,但是地图可能不会. map ht ...

  3. 百度地图的简单开发之方向传感器实现定位功能

    今天我们来谈下百度地图的定位功能,在此之前我已经将百度地图的基本地图大概说了下,其实百度地图的基本功能还有很多的内容.感兴趣的可以到百度地图的开发者的官网看看.今天就开始来讲下百度地图中的定位功能. ...

  4. 百度地图android绘图类,百度地图绘制点、图形

    目标: 1,指定经纬度,显示一个图片,点击图片能显示相应的介绍信息 2,当前屏幕把所有指定的坐标点都显示出来 预览效果:添加了四个点,红色定位图片表示出来 实现 准备条件: 配置百度地图,只要能fin ...

  5. iOS 使用百度地图,仿滴滴打车的定位方法。拖动时时定位

    先看下效果,没有录屏,放张图片,如果想体验效果可以看看滴滴打车的定位,我这里没有写动画效果 参考http://bbs.lbsyun.baidu.com/forum.php?mod=viewthread ...

  6. 百度地图拖动标注后获取坐标

    本来想用图吧的API来做的,结果弄了下,在手机上弄不了.换用百度地图了..本功能个人觉得在很多地方用到,先记下来,省得每次都得翻地图API文档一点一点弄. 功能表现为: 地图一开始打开就定位到你的附近 ...

  7. 限制百度地图拖动范围限制,当超如范围时自动返回

    限制百度地图拖动范围限制,当超如范围时自动返回 背景 最近利用百度离线地图加载世界地图,但发现下载的区域只是世界地图一块,当拖动地图范围超过想要的范围时,就会出现背景块为白色: 如图 解决思路1:百度 ...

  8. 百度地图实现公司位置的定位,可拖动修改公司位置。

    百度地图实现公司位置的定位,可拖动修改公司位置.只需要维护x轴和Y轴的数据到数据库就可以了 可拖动,可搜索. <html><head><script src=" ...

  9. html地图根据坐标定位,百度地图js根据经纬度定位和拖动定位点

    &lt我自址哈这工边识框处己按后大都加控不架的;/scrip比抖朋要插支一圈不者地器享说几t> 定位 body, html, #allmap { width: 100%; height: ...

最新文章

  1. Linux下的各种文件阅读器
  2. 对软件体系结构的认识
  3. 步步为营-72-asp.net简单练习(通过webForm实现一些简单实例)
  4. .NET WebBrowser不与IE或其他进程共享cookie(WebBrowser独立cookie方法)
  5. 迷你图标集大集合:5000+ 30套免费的图标
  6. python f.write 保存图片到路径_Python实现生成图片路径和对应标签的方式
  7. windows获取系统补丁+匿名管道
  8. 搭建小程序表情包教程
  9. eclipse——Error exists in required project Proceed with launch?
  10. django部署到linux上不显示.svg图标处理方法
  11. 基于钉钉小程序做一个记事本
  12. CCNA--路由器常用命令
  13. Unity2D:简单人物纸娃娃换装实现(一) 服装的变换
  14. Rust_lings
  15. 【BeEF】Ubuntu 20.04安装BeEF
  16. 操作系统期末实验:多用户二级文件系统
  17. 双系统linux哪种好,双系统安装实战,这个Linux系统超级简单
  18. 新拉下来的vue项目怎么跑起来?
  19. 什么是库尼乌斯(the Cuneus)
  20. python数据与挖掘实战学习:实战篇 第八章中医证型关联规则挖掘笔记

热门文章

  1. 如何在网上找到并下载你想要的软件
  2. 用 Python 爬取糗事百科
  3. 你不得不关注的5 大Android 开发技术——2020
  4. 现在有什么地推项目_市场推广中谈到地推,地推是什么意思?
  5. vue3+ts+ant-table横向表格数据实现对单元格过滤之后的数据进行标红
  6. Activiti的学习
  7. MQL4自编指标学习1
  8. 使用php创建WebSocket服务
  9. i5 1155g7和i5 11300h 选哪个好
  10. 光电倍增管国产型号及相关知识