功能:在Android中实现可拖动按钮,同时实现按钮的点击功能

相关问题:

  1. 按钮拖动的界限限定。
  2. 按钮单击和拖动之间的冲突。
  3. 在界面未显示之前,获得View的高/宽。

问题描述:

  1. 如果不为按钮的拖动范围设定界限,按钮将可以被拖出触摸屏,影响操作。如果程序实现了位置的记录功能(这里暂不实现),当按钮的显示范围超出显示屏时,按钮可能会变形。
  2. 在拖动的时间中,程序将会首先触发事件的顺序为:ACTION_DOWN -> ACTION_MOVE -> ACTION_UP,在触发ACTION_DOWN时,系统将会在ACTION_UP结束后,触发按钮被点击的事件(按钮点击事件被触发的条件略),造成拖动事件和单机事件之间的冲突。
  3. 在Activity的onCreate()中,各个View并未被重画,所以不过调用View.getHeight()还是调用View.getMeasuredHeight(),所得到的结果都为0。只有在onDraw中,View将会被重画,但是此时往往对程序来说,获取数据有显得太晚。

解决方法:

  1. 通过对按钮实现setOnTouchListener()监听器,来使得按钮可以被任意拖动,在监听器中的ACTION_MOVE事件的处理中,对按钮实现重画和对拖动的界限的限定。
  2. 通过取得ACTION_UP与ACTION_DOWN之间按钮的位移来确定按钮所应该触发的事件,并通过设定位移的大小来避免误操作。
  3. 通过获取界面中的ViewTree的监听器,来获得在View被重画前,它被测量出的高/宽。

源代码:

  1.布局文件(activity_main.xml)

______________________________________________________________________________________________________

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity" >

<Button
android:id="@+id/movebtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />

</RelativeLayout>

______________________________________________________________________________________________________

  2.界面代码(MainActivity.java)

______________________________________________________________________________________________________

package com.luxl.slideandtouch;

import android.os.Bundle;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

private Button movebtn;        //可拖动按钮
private boolean clickormove = true;  //点击或拖动,点击为true,拖动为false
private int downX, downY;      //按下时的X,Y坐标
private boolean hasMeasured = false;  //ViewTree是否已被测量过,是为true,否为false
private View content;          //界面的ViewTree
private int screenWidth,screenHeight;  //ViewTree的宽和高

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

content = getWindow().findViewById(Window.ID_ANDROID_CONTENT);//获取界面的ViewTree根节点View

DisplayMetrics dm = getResources().getDisplayMetrics();//获取显示屏属性
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;

ViewTreeObserver vto = content.getViewTreeObserver();获取ViewTree的监听器
vto.addOnPreDrawListener(new OnPreDrawListener() {

@Override
public boolean onPreDraw() {

// TODO Auto-generated method stub
if(!hasMeasured)
{

screenHeight = content.getMeasuredHeight();//获取ViewTree的高度
hasMeasured = true;//设置为true,使其不再被测量。

}
return true;//如果返回false,界面将为空。

}

});
movebtn = (Button) findViewById(R.id.movebtn);
movebtn.setOnTouchListener(new OnTouchListener() {//设置按钮被触摸的时间

int lastX, lastY; // 记录移动的最后的位置

@Override
public boolean onTouch(View v, MotionEvent event) {

// TODO Auto-generated method stub
int ea = event.getAction();//获取事件类型
switch (ea) {
case MotionEvent.ACTION_DOWN: // 按下事件

lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
downX = lastX;
downY = lastY;
break;

case MotionEvent.ACTION_MOVE: // 拖动事件

// 移动中动态设置位置
int dx = (int) event.getRawX() - lastX;//位移量X
int dy = (int) event.getRawY() - lastY;//位移量Y
int left = v.getLeft() + dx;
int top = v.getTop() + dy;
int right = v.getRight() + dx;
int bottom = v.getBottom() + dy;

//++限定按钮被拖动的范围
if (left < 0) {

left = 0;
right = left + v.getWidth();

}
if (right > screenWidth) {

right = screenWidth;
left = right - v.getWidth();

}
if (top < 0) {

top = 0;
bottom = top + v.getHeight();

}
if (bottom > screenHeight) {

bottom = screenHeight;
top = bottom - v.getHeight();

}

//--限定按钮被拖动的范围

v.layout(left, top, right, bottom);//按钮重画

// 记录当前的位置
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;

case MotionEvent.ACTION_UP: // 弹起事件

  //判断是单击事件或是拖动事件,位移量大于5则断定为拖动事件

if (Math.abs((int) (event.getRawX() - downX)) > 5
|| Math.abs((int) (event.getRawY() - downY)) > 5)

clickormove = false;

else

clickormove = true;

break;

}
return false;

}

});
movebtn.setOnClickListener(new OnClickListener() {//设置按钮被点击的监听器

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if (clickormove)

Toast.makeText(MainActivity.this, "single click",
Toast.LENGTH_SHORT).show();

}

});

}

}

android实现可拖动按钮的更多相关文章

  1. Android自定义可拖动的悬浮按钮

    在页面上随意拖动的按钮 public class MoveScaleRotateView extends RelativeLayout { private Context mContext; //默认 ...

  2. Android 空心和实心按钮

    Android 空心和实心按钮 做界面时 有时老要用到这种按钮 动画如下 实心的 <?xml version="1.0" encoding="utf-8" ...

  3. Android ImageButton Example 图片按钮

    Android ImageButton Example 图片按钮 使用“android.widget.ImageButton” 展现一个具有背景图片的按钮 本教程将展现一个具有名字为 c.png背景图 ...

  4. Android 按下电源按钮关闭小学习过程的整个长度

    Android 按下电源按钮关闭小学习过程的整个长度 近期研究了一下android关机跟又一次启动功能,看了一些长按电源键到弹出关机对话框,到真正关机的一系列处理过程. 首先还是来看看这个长按电源键都 ...

  5. Android实现渐显按钮的左右滑动效果

    本示例演示在Android中实现带渐显按钮的左右滑动效果. 关于滑动效果,在我的上一篇博文中提到过,有兴趣的朋友可以访问: http://www.cnblogs.com/hanyonglu/archi ...

  6. android开发_文本按钮 与 输入框

    1 TextView:    属性与值 android:text="文本" android:textSize="20sp"              //sp为 ...

  7. Ionic2 下处理 Android 设备下返回按钮的事件

    原文发表于我的技术博客 本文分享了 Ionic2 下处理 Android 设备下返回按钮的事件,供参考. 原文发表于我的技术博客 代码中我分享了如何捕捉 Ionic2 项目在 Android 设备下返 ...

  8. (转载)Android之有效防止按钮多次重复点击的方法(必看篇)

    为了防止测试妹子或者用户频繁点击某个按钮,导致程序在短时间内进行多次数据提交or数据处理,那到时候就比较坑了~ 那么如何有效避免这种情况的发生呢? 我的想法是,判断用户点击按钮间隔时间,如果间隔时间太 ...

  9. android中SeekBar拖动进度条的使用及事件监听

    下面和大家分享一下android中SeekBar拖动进度条的使用,以及事件监听.拖动进度条的事件监听需要实现SeekBar.OnSeekBarChangeListener接口,调用SeekBar的se ...

随机推荐

  1. BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会 树形DP

    [Usaco2010 Mar]gather 奶牛大集会 Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会.每个奶牛居住在 N(1 ...

  2. CSS图片翻转例子

                      dfdfdfdfdf <!DOCTYPE html> <html> <head> <meta charset=" ...

  3. WinForm打包后皮肤无效(解决方案)

    今天在项目中用到了SkinEngine,遇到了一点问题,总结出点心得: 问题: 为什么我们在开发中皮肤还是显示的,但是打包后就没有效果了? 我也遇到了同样的问题,一开始以为是路径的问题: 我不知道大家 ...

  4. 教你21天学会C++ (有图有真相)

    这张图,是在一位有十多年开发经验的资深前辈博客里看到的,觉得很有趣,分享之~ 这位大神的博客是:http://coolshell.cn 理论是可行的,当你刚开始学习C++,到第21天的时候出门千万要小 ...

  5. 2012的数据库 select @@version 都是说版本为2008 R2

    如图 我使用的是sqlserver2012登录的,select @@version 查询出来的却是2008 ,而且附加不了2012的数据库. 在网上搜到解决方法:1确认是否安装了2012(废话没安装是 ...

  6. 北大ACM(POJ1014-Dividing)

    Question:http://poj.org/problem?id=1014 问题点:抽屉原理.dfs.多重背包. Memory: 248K Time: 16MS Language: C++ Res ...

  7. UI3_UIView自动布局

    // // ViewController.m // UI3_UIView自动布局 // // Created by zhangxueming on 15/7/1. // Copyright (c) 2 ...

  8. 了解常见的开源协议(BSD, GPL, LGPL,MIT)

    一直对各种开源协议比较模糊, 特意在网上搜索了一下资料, 整理总结,以作记录 如果不喜欢长篇大论的话, 看下图就可以了 基本概念了解: 1. Contributors 和 Recipients Con ...

  9. HDU1106 排序

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1106   Problem Description 输入一行数字,如果我们把这行数字中的‘5’都看成空格 ...

  10. QQ截图工具提取

    今晚关了QQ,突然想截个图,但是呢又不想打开QQ了,于是在网上搜索截图工具,下载了几个,感觉都没有QQ截图好用.索性直接百度QQ截图工具提取,看到有些网站上有提取的,里面的文件有点多,不是我中意的,突 ...