zoukankan      html  css  js  c++  java
  • android实现可拖动按钮

    功能:在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();

    }

    });

    }

    }

  • 相关阅读:
    编译java蛋疼的一小时
    最简单的Java Applet程序
    枚举任意进程内核对象句柄的方法
    RvmTranslator7.3.2
    PipeCAD
    Open CASCADE Technology 7.5.0 released
    IsoAlgo 环路处理
    OpenCASCADE STEP Color
    RvmTranslator 3D PDF in Ubuntu
    IsoAlgo Symbols
  • 原文地址:https://www.cnblogs.com/ScorchingSun/p/3627330.html
Copyright © 2011-2022 走看看