<?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:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.wtz.verticalslideview.VerticalSlideView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00f">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tabicon"/>
</com.example.wtz.verticalslideview.VerticalSlideView>
</RelativeLayout>
package com.example.wtz.verticalslideview;
import android.content.Context;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
public class VerticalSlideView extends ViewGroup {
private View mChildView;
private float mStartY,mStartX;
public VerticalSlideView(Context context) {
super(context);
}
public VerticalSlideView(Context context, AttributeSet attrs) {
super(context, attrs);
}
//确定控件的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//1 获得mode和size
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
mChildView = getChildAt(0);
//测量下子控件
measureChildren(widthMeasureSpec, heightMeasureSpec);
//2 判断mode,通过mode去设置对应的合理的size
switch (widthMode) {
case MeasureSpec.AT_MOST:
//宽度如果是wrap_content的话,设置宽度为子控件的宽度
widthSize = mChildView.getMeasuredWidth();
break;
case MeasureSpec.EXACTLY:
break;
}
switch (heightMode) {
case MeasureSpec.AT_MOST:
//高度如果是wrap_content的话,设置高度为整个页面的高度
heightSize = getResources().getDisplayMetrics().heightPixels/2;
break;
case MeasureSpec.EXACTLY:
break;
}
//3 setMeasuredDimension 设置控件的大小
setMeasuredDimension(widthSize, heightSize);
}
int mTop = 0;
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//去布局内部的子控件(就是那个图片滑块)
Log.d(getClass().getSimpleName(), "onLayout: mTop: " + mTop);
//判断一下是否超过边界
if(mTop<0){
//上边界
mTop = 0;
}
Log.d(getClass().getSimpleName(), "onLayout: 下边界" + (getMeasuredHeight()-mChildView.getMeasuredHeight()));
if(mTop>getMeasuredHeight()-mChildView.getMeasuredHeight()){
//下边界
mTop = getMeasuredHeight()-mChildView.getMeasuredHeight();
}
mChildView.layout(0, mTop, mChildView.getMeasuredWidth(), mTop+mChildView.getMeasuredHeight());
}
//写一下触摸事件逻辑
@Override
public boolean onTouchEvent(MotionEvent event) {
//触摸的几种常见类型:按下 移动 抬起
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
//按下
mStartY = event.getY();
mStartX = event.getX();
Log.d(getClass().getSimpleName(), "onTouchEvent:按下 "
+" startY: "+ mStartY);
//如果按在空白的地方,就不再继续往下面做处理了,直接return false
//拿到图片子控件所在的位置矩形,如果按下的坐标不在子控件位置矩形内,认为是按在空白的地方
RectF rectF = new RectF(0, mTop, mChildView.getMeasuredWidth(), mTop + mChildView.getMeasuredHeight());
if(!rectF.contains(mStartX,mStartY)){
return false;
}
break;
case MotionEvent.ACTION_MOVE:
//移动
float moveY = event.getY();
float dy = moveY - mStartY;
mTop+=dy;
//以前的终点作为现在的起点
mStartY = moveY;
// Log.d(getClass().getSimpleName(), "onTouchEvent:移动 "
// +" moveY: "+moveY);
break;
case MotionEvent.ACTION_UP:
//抬起
break;
default:
break;
}
//需要让控件重新去布局一下
requestLayout();
//按下时 ,记录坐标,作为起点
//移动,不断去获得坐标,终点-起点,获得偏移量(位移值),拿着位移值,去在其他地方去使用
//抬起
//如果不为true,那么就只会执行down逻辑,后面的move啥的就不走了
return true;
}
}
