Android——控件跟随手指移动

本文详细介绍了在Android开发过程中如何实现任意控件跟随手指触摸移动的功能,并通过分析一个现有代码实例中的Bug,提出了改进方案。文中包括核心思路、关键代码解析以及避免控件变形的解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android开发中遇到过的坑——控件跟随手指移动

思路

实现任意控件跟随手指触摸移动。核心思路监听onTouch事件,在ACTION_MOVE中改变控件的坐标。思路虽然简单,但其中还有一些坑。
本文的思路借鉴了http://blog.youkuaiyun.com/actual_/article/details/8582313这位博主的代码,但他的代码有个Bug,即当拖动控件到屏幕中间位置时控件会变形,分析其代码,主要问题出现在:

case MotionEvent.ACTION_MOVE:  
            RelativeLayout.LayoutParams layoutParams =    (RelativeLayout.LayoutParams) view  
                    .getLayoutParams();  
            layoutParams.leftMargin = X - _xDelta;  
            layoutParams.topMargin = Y - _yDelta;  
            layoutParams.rightMargin = -250;  
            layoutParams.bottomMargin = -250;  
            view.setLayoutParams(layoutParams);  
            break;  

其中设置了控件上、下、左、右元素间隔的距离,从而完成在RelativeLayout布局中对于控件位置的设置,但是当左右间隔或上下间隔之和不对的时候,则会挤压控件的长宽。

这里换一个思路,其实只设置控件距上、左元素的距离即可完成RelativeLayout布局中控件位置的设置,并设置控件的长宽,保持其形状大小不变。

case MotionEvent.ACTION_MOVE:  
                int dx = (int) event.getRawX() - lastX;
                int dy = (int) event.getRawY() - lastY;
                int left = view.getLeft() + dx;
                int top = view.getTop() + dy;
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view 
                        .getLayoutParams();  
                layoutParams.height=IMAGE_SIZE;
                layoutParams.width = IMAGE_SIZE;
                layoutParams.leftMargin =left;  
                layoutParams.topMargin =top;  
                view.setLayoutParams(layoutParams);
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;  

主要代码

MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;


public class MainActivity extends AppCompatActivity implements OnTouchListener {
    ImageView _view,_view2;  
    ViewGroup _root;  
    private int lastX, lastY;
    final static int IMAGE_SIZE = 72; 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        _root = (ViewGroup) findViewById(R.id.root);  

        _view = (ImageView) findViewById(R.id.id_text);  
        _view2 = (ImageView) findViewById(R.id.id_text2); 

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(  
                IMAGE_SIZE, IMAGE_SIZE);  
        layoutParams.leftMargin = IMAGE_SIZE;  
        layoutParams.topMargin = IMAGE_SIZE;  

        _view.setLayoutParams(layoutParams);  
        _view.setOnTouchListener(this); 
        RelativeLayout.LayoutParams layoutParams2 = new RelativeLayout.LayoutParams(  
                IMAGE_SIZE, IMAGE_SIZE);  
        layoutParams2.leftMargin = 3*IMAGE_SIZE;  
        layoutParams2.topMargin = IMAGE_SIZE;  

        _view2.setLayoutParams(layoutParams2);  
        _view2.setOnTouchListener(this);  
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

     public boolean onTouch(View view, MotionEvent event) {  
            final int X = (int) event.getRawX();  
            final int Y = (int) event.getRawY();  
            switch (event.getAction() & MotionEvent.ACTION_MASK) {  
            case MotionEvent.ACTION_DOWN:  
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view  
                        .getLayoutParams();   
                break;  
            case MotionEvent.ACTION_UP:  
                break;  
            case MotionEvent.ACTION_POINTER_DOWN:  
                break;  
            case MotionEvent.ACTION_POINTER_UP:  
                break;  
            case MotionEvent.ACTION_MOVE:  
                int dx = (int) event.getRawX() - lastX;
                int dy = (int) event.getRawY() - lastY;
                int left = view.getLeft() + dx;
                int top = view.getTop() + dy;
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view 
                        .getLayoutParams();  
                layoutParams.height=IMAGE_SIZE;
                layoutParams.width = IMAGE_SIZE;
                layoutParams.leftMargin =left;  
                layoutParams.topMargin =top;  
                view.setLayoutParams(layoutParams);
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;  
            }  
            _root.invalidate();  
            return true;  
        }  
}

activity_main.xml

这里写代码片<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"  
    android:id="@+id/root"  
    tools:context=".MainActivity" >  

    <ImageView  
        android:id="@+id/id_text"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerHorizontal="true"  
        android:layout_centerVertical="true"  
        android:background="@drawable/pin2"
         />  
   <ImageView  
        android:id="@+id/id_text2"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerHorizontal="true"  
        android:layout_centerVertical="true"  
        android:background="@drawable/pin2"
        /> 
</RelativeLayout>  
android移动控件 /** * 用于判断view的移动 * @param view * @param event * @return */ @Override public boolean onTouch(View view, MotionEvent event) { final int X = (int) event.getRawX(); final int Y = (int) event.getRawY(); switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: if(lParams.leftMargin<0){//判断控件是否半隐藏状态 lParams.leftMargin = 0; }else if(lParams.topMargin<0){ lParams.topMargin=0; }else if(X -_xDelta> screenWidth - width){ lParams.leftMargin = screenWidth-width; } _xDelta = X - lParams.leftMargin; _yDelta = Y - lParams.topMargin; StartX = X; StartY = Y; // Log.e(TAG,"_xDelta "+_xDelta+" _yDelta "+_yDelta+" lParams.rightMargin "+lParams.rightMargin); break; case MotionEvent.ACTION_UP: //关键部分:移动距离较小,视为onclick点击行为 if (Math.abs(X - StartX) < 1.5 && Math.abs(Y - StartY) < 1.5){//计算器弹出 //这放点击后的逻辑代码 } break; case MotionEvent.ACTION_POINTER_DOWN: break; case MotionEvent.ACTION_POINTER_UP: break; case MotionEvent.ACTION_MOVE: // RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view // .getLayoutParams(); if(X - _xDelta<0 - width/2){ lParams.leftMargin = 0- width/2; }else if(X -_xDelta> screenWidth - width/2){ lParams.leftMargin = screenWidth - width/2; }else{ lParams.leftMargin = X - _xDelta; } if(Y - _yDelta<0 - height/2){ lParams.topMargin = 0 - height/2; }else if(Y -_yDelta > screenHeight - height-NavigationBarheight){ lParams.topMargin = screenHeight - height-NavigationBarheight; }else{ lParams.topMargin = Y - _yDelta; } lParams.rightMargin = -250; lParams.bottomMargin = -250; view.setLayoutParams(lParams); break; } background.invalidate(); return true; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值