自定义View之箭头的上下滑动布局

先看效果:

 

demo地址:https://github.com/18360981992/SlideView-Android

需求挺简单的,就是一个拖动指定控件,然后滑动展示下一层的内容!但就是这简单的需求也让本人费了半天的劲。

下面我就说一说我的想法吧,一开始我的想法是写个自定义的的listview,利用listview中的“视察特效”的思路来解决,等我好不容易写完拿去交差,结果迎来的却是一句:“与效果不符,我不需要整个页面的滑动,只要那一点点的小图标,小控件可以进行滑动”!当时一万头“草泥马。。。”

没办法,回来继续吧!

既然是实现拖动,肯定离不开手势,基本的手势“三要素”==》按下,抬起,移动

有了这三要素肯定还是不够的,还欠缺一个实时的控件位置的改变 ==》layout(l , t ,r ,b);  百度一下这个方法,有详细的

说明,比咱强的多!!

首先实现控件跟随手指的移动而改变位置,那么肯定是在手势监听中的“移动事件”是没跑了,

case MotionEvent.ACTION_MOVE:// 手指在屏幕上移动对应的事件
    int y = (int) event.getRawY();
    // 获取手指移动的距离
    int dy = y - sy;
    Log.i("jba","dy=="+dy);
   
    // 得到textView最开始的各顶点的坐标
    int l = tuodong.getLeft();
    int r = tuodong.getRight();
    int t = tuodong.getTop();
    int b = tuodong.getBottom();
   
    tuodong.layout(l , t + dy, r , b + dy);// 更改textView在窗体的位置

    sy = (int) event.getRawY();  // 获取移动后的位置 用来实时更新当前位置  这行代码非常重要
    break;

以上代码就可以非常轻松的实现“控件跟随手指的移动而改变位置”,但是很显然距离我们想要的效果还差很远,那么就接着看!

控件位置的改变,我们已经实现了,但是会发现,有的时候滑动速度或者距离过猛,过大都会导致我们控件超出我们手机屏幕,所以我们需要为手指的滑动设置上范围,这个范围大家心里肯定都有一个打算,纠结的应该是在那个事件中设置吧!!

仔细分析一下,我们滑动的时候,控件肯定是跟着一起动的,手指动到哪里,那控件也就应该跟到哪里,也就是说我的手指即使滑动的超出了屏幕,那么控件也应该,也可以超出屏幕,这个肯定是没毛病的,也是合理的。那么再换言之,我们的范围设置也就不可以在“移动的事件”中进行,那么在哪里呢?====抬起!没错,就是抬起的事件中!

case MotionEvent.ACTION_UP:
    // 得到imageView最开始的各顶点的坐标
    int lup = tuodong.getLeft();
    int rup = tuodong.getRight();
    int tup = tuodong.getTop();
    int bup = tuodong.getBottom();
    Log.i("jba","tup=="+tup+",bup=="+bup);
    // 限制手势的活动范围
    if(bup >= t_yuan){ // 从最底部拖动 是否到达活动范围内
        tuodong.layout(lup , t_yuan, rup , b_yuan);
        bianhua_height=0;
        linearParams.height = bianhua_height;
        bianhua.setLayoutParams(linearParams); //使设置好的布局参数应用到控件
    }else if(tup <= 600+tuodong_height){   // 从最顶部拖动  是否到达活动范围内  注:这里的600只是个量词  大家可以根据自己的需求进行更改 比如屏幕高度的百分之多少
        tuodong.layout(lup ,600, rup , tuodong_height+600);
        bianhua_height = tuodong_height - b_yuan + 600;
        linearParams.height =Math.abs(bianhua_height);
        bianhua.setLayoutParams(linearParams); //使设置好的布局参数应用到控件
    }else if( bup<t_yuan && bup>600+tuodong_height && type==2){ // 向上 并且活动范围在最大和最小之间
        tuodong.layout(lup ,600, rup , tuodong_height+600);
        bianhua_height = tuodong_height - b_yuan + 600;
        linearParams.height =Math.abs(bianhua_height);
        bianhua.setLayoutParams(linearParams); //使设置好的布局参数应用到控件
    }else if(tup < t_yuan-tuodong_height && tup > 600+tuodong_height && type==1){ // 向下  并且活动范围在最大和最小之间
        tuodong.layout(lup , t_yuan, rup , b_yuan);
        bianhua_height=0;
        linearParams.height = bianhua_height;
        bianhua.setLayoutParams(linearParams); //使设置好的布局参数应用到控件
    }
    break;

关于以上的代码,我在这给大家画图来解释一下我的思路:

 

好了,现在范围也设定好了,剩下的就是一些滑动效果的优化了,比如回弹的效果啊,滑动的速度啊,等等,这些呢,我认为都是次要的,并且我也已经写到我的demo中了,整个效果中最重要的就是这两个事件的处理了,只要把这两个事件给理解透了,处理好了,别的就都是毛毛雨了!!

附上demo地址:https://github.com/18360981992/SlideView-Android

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Kotlin自定义View中,可以通过重写`onInterceptTouchEvent`方法来限制子滑动控件的滑动。在这个方法中,你可以判断是否要拦截事件,并返回`true`或`false`来决定是否拦截事件。如果返回`true`,则表示拦截事件,子滑动控件将无法滑动;如果返回`false`,则表示不拦截事件,子滑动控件可以正常滑动。 下面是一个示例,展示如何在自定义View中限制子滑动控件的滑动。这个示例中创建了一个`CustomView`类,它包含一个`RecyclerView`作为子视图。我们想要在用户水平滑动`CustomView`时,防止`RecyclerView`的水平滑动,只允许垂直滑动: ``` class CustomView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { private var initialX = 0f private var initialY = 0f private val recyclerView: RecyclerView init { LayoutInflater.from(context).inflate(R.layout.custom_view, this, true) recyclerView = findViewById(R.id.recyclerView) } override fun onInterceptTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { initialX = event.x initialY = event.y return false } MotionEvent.ACTION_MOVE -> { val dx = abs(event.x - initialX) val dy = abs(event.y - initialY) return dy > dx } else -> return super.onInterceptTouchEvent(event) } } } ``` 在`onInterceptTouchEvent`方法中,我们首先记录了用户按下手指时的坐标。然后,在用户移动手指时,我们计算水平和垂直方向上的滑动距离,并比较它们。如果垂直方向上的滑动距离大于水平方向上的滑动距离,则返回`true`,表示拦截事件,防止`RecyclerView`的滑动。否则,返回`false`,表示不拦截事件,`RecyclerView`可以正常滑动。 需要注意的是,在这个示例中,我们使用了`LayoutInflater`来从XML布局文件中获取`RecyclerView`视图。如果你使用了不同的方式来创建子视图,请相应地修改初始化代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值