首页 > 其他分享 >自定义ViewGroup 实现拖动跟快速滚动的效果

自定义ViewGroup 实现拖动跟快速滚动的效果

时间:2023-03-20 13:02:30浏览次数:47  
标签:ViewGroup 自定义 MotionEvent 拖动 move int excess import android


  之前做到个项目要类似listView或者GridView中的控件移动的效果(主屏上所有程序列表上的效果):
1:子控件跟着手指移动
2:快速拨动一下,根据拨动的速度 滑动过去
3:拖过头,放手后弹回去

   但是用listView或者GridView又不好实现项目要求的其他效果..于是继承viewGroup实现以上效果。

   既然要获取拨动速度,并以此滑动。首先想到了OnGestureListener 这个接口,实现这个接口并实现其onFling方法.

  还要控制拖动。重写onTouchEvent方法,并在其中控制内容控件的拖动,反弹等效果

这时候基本已经完成了。。。。测试了一下了,发现了一个问题,当手指点在viewGroup上

进行 拖动是没问题的,但是在子控件上就不行了,这是事件响应的问题 那么还要做如面的处

理:实现onInterceptTouchEvent方法,判断是拖动事件时 ,将事件传递下去。

import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.GestureDetector.OnGestureListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Scroller;
import android.widget.Toast;
import android.widget.ImageView.ScaleType;

public class MyViewGroup extends ViewGroup implements OnGestureListener {

private float mLastMotionY;// 最后点击的点
private GestureDetector detector;
int move = 0;// 移动距离
int MAXMOVE = 850;// 最大允许的移动距离
private Scroller mScroller;
int up_excess_move = 0;// 往上多移的距离
int down_excess_move = 0;// 往下多移的距离
private final static int TOUCH_STATE_REST = 0;
private final static int TOUCH_STATE_SCROLLING = 1;
private int mTouchSlop;
private int mTouchState = TOUCH_STATE_REST;
Context mContext;


public MyViewGroup(Context context) {
super(context);
mContext = context;
// TODO Auto-generated constructor stub
setBackgroundResource(R.drawable.pic);
mScroller = new Scroller(context);
detector = new GestureDetector(this);

final ViewConfiguration configuration = ViewConfiguration.get(context);
// 获得可以认为是滚动的距离
mTouchSlop = configuration.getScaledTouchSlop();

// 添加子View
for (int i = 0; i < 48; i++) {
final Button MButton = new Button(context);
MButton.setText("" + (i + 1));
MButton.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(mContext, MButton.getText(), Toast.LENGTH_SHORT).show();
}
});
addView(MButton);
}
}

@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
// 返回当前滚动X方向的偏移
scrollTo(0, mScroller.getCurrY());
postInvalidate();
}
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();

final float y = ev.getY();
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:

mLastMotionY = y;
mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
: TOUCH_STATE_SCROLLING;
break;
case MotionEvent.ACTION_MOVE:
final int yDiff = (int) Math.abs(y - mLastMotionY);
boolean yMoved = yDiff > mTouchSlop;
// 判断是否是移动
if (yMoved) {
mTouchState = TOUCH_STATE_SCROLLING;
}
break;
case MotionEvent.ACTION_UP:
mTouchState = TOUCH_STATE_REST;
break;
}
return mTouchState != TOUCH_STATE_REST;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {

// final int action = ev.getAction();

final float y = ev.getY();
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.forceFinished(true);
move = mScroller.getFinalY();
}
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
if (ev.getPointerCount() == 1) {

// 随手指 拖动的代码
int deltaY = 0;
deltaY = (int) (mLastMotionY - y);
mLastMotionY = y;
Log.d("move", "" + move);
if (deltaY < 0) {
// 下移
// 判断上移 是否滑过头
if (up_excess_move == 0) {
if (move > 0) {
int move_this = Math.max(-move, deltaY);
move = move + move_this;
scrollBy(0, move_this);
} else if (move == 0) {// 如果已经是最顶端 继续往下拉
Log.d("down_excess_move", "" + down_excess_move);
down_excess_move = down_excess_move - deltaY / 2;// 记录下多往下拉的值
scrollBy(0, deltaY / 2);
}
} else if (up_excess_move > 0)// 之前有上移过头
{
if (up_excess_move >= (-deltaY)) {
up_excess_move = up_excess_move + deltaY;
scrollBy(0, deltaY);
} else {
up_excess_move = 0;
scrollBy(0, -up_excess_move);
}
}
} else if (deltaY > 0) {
// 上移
if (down_excess_move == 0) {
if (MAXMOVE - move > 0) {
int move_this = Math.min(MAXMOVE - move, deltaY);
move = move + move_this;
scrollBy(0, move_this);
} else if (MAXMOVE - move == 0) {
if (up_excess_move <= 100) {
up_excess_move = up_excess_move + deltaY / 2;
scrollBy(0, deltaY / 2);
}
}
} else if (down_excess_move > 0) {
if (down_excess_move >= deltaY) {
down_excess_move = down_excess_move - deltaY;
scrollBy(0, deltaY);
} else {
down_excess_move = 0;
scrollBy(0, down_excess_move);
}
}
}
}
break;
case MotionEvent.ACTION_UP:
// 多滚是负数 记录到move里
if (up_excess_move > 0) {
// 多滚了 要弹回去
scrollBy(0, -up_excess_move);
invalidate();
up_excess_move = 0;
}
if (down_excess_move > 0) {
// 多滚了 要弹回去
scrollBy(0, down_excess_move);
invalidate();
down_excess_move = 0;
}
mTouchState = TOUCH_STATE_REST;
break;
}
return this.detector.onTouchEvent(ev);
}

int Fling_move = 0;

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
//随手指 快速拨动的代码
Log.d("onFling", "onFling");
if (up_excess_move == 0 && down_excess_move == 0) {

int slow = -(int) velocityY * 3 / 4;
mScroller.fling(0, move, 0, slow, 0, 0, 0, MAXMOVE);
move = mScroller.getFinalY();
computeScroll();
}
return false;
}

public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return true;
}

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
return false;
}

public void onShowPress(MotionEvent e) {
// // TODO Auto-generated method stub
}

public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}

public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
int childTop = 0;
int childLeft = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.setVisibility(View.VISIBLE);
child.measure(r - l, b - t);
child
.layout(childLeft, childTop, childLeft + 80,
childTop + 80);
if (childLeft < 160) {
childLeft += 80;
} else {
childLeft = 0;
childTop += 80;
}
}
}
}

}



import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

public class Workspace extends ViewGroup {

public Workspace(Context context) {
super(context);
// TODO Auto-generated constructor stub
addView(new MyViewGroup(context));
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
child.measure(r - l, b - t);
child.layout(0, 0, 320, 480);
}
}

}



import android.app.Activity;
import android.os.Bundle;

public class MoveViewGroup extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new Workspace(this));

}
}


标签:ViewGroup,自定义,MotionEvent,拖动,move,int,excess,import,android
From: https://blog.51cto.com/u_5454003/6132604

相关文章

  • Android自定义长按事件
    Android系统自带了长按事件,setOnLongClickListener即可监听。但是有时候,你不希望用系统的长按事件,比如当希望长按的时间更长一点的时候。这时候就需要......
  • Three.js自定义shader实现离相机越近越透明效果
    constcustomShader=newTHREE.ShaderMaterial({uniforms:{},defines:{nearDis:0.3},transparent:true,side:THREE.DoubleSide,vertexShader:......
  • Java stream sorted自定义排序规则实现多字段排序
      Stream提供了丰富的操作(中间操作和终端操作)集合元素的轮子,但Stream流操作不影响原始集合数据,执行结果是一个新的集合对象。在《Javastreamsorted使用Comparator进......
  • fastadmin 自定义build_toolbar按钮
    fastadmin自定义build_toolbar按钮何渊渊于2020-09-2311:13:31发布1930收藏4分类专栏:fastadmin文章文章标签:javascriptphp版权fastadmin同时被2个专栏收......
  • 自定义异常回滚@Transactional注解
    //重点关注的是@Transactional注解和TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()@Override@Transactional(rollbackFor=RuntimeExcep......
  • 【Android开发】用户界面设计-开发自定义的View
    效果图:Android中,所有的UI界面都是由View类和ViewGroup类及其子类组合而成的。View是所有UI组件的基类(父类),为ViewGroup类是容纳这些UI组件的容器,其本身也是View的子类。关......
  • Visual Studio自定义代码片段
    问题描述VisualStudio提供了CodeSnippetManager功能,这使得用户可以自定义代码片段。用户可以在CodeSnippetManager中创建自己的代码片段,并指定一个唯一的提示符。一......
  • 自定义指令
    Vue是一个流行的JavaScript框架,它允许开发人员构建动态的用户界面和单页应用程序。Vue的灵活性使其成为开发人员的首选框架之一,其中一个重要的原因是其能够自定义指令,以便......
  • 使用Vue自定义组件完成10×10图片表格的点击效果
    1.创建一个web项目,使用<script>引入Vue.js代码如下:<scripttype="text/javascript"src="js/vue.js"></script> 2.创建vue实例<divid="app"></div><scrip......
  • Vue指令:内置指令和自定义指令
    Vue指令Vue指令指的是,以v-开头的一组特殊语法内置指令v-textv-text指令的作用是:设置标签的内容默认写法会替换全部内容,差值表达式{{}}只会替换指定内容内部......