demo效果如下图:

android 图片上下居中 android怎么让图片移动_ide


拖动图片时需要监听整个屏幕,识别触摸点位置,位置在图片上拖动时,就移动图片;触摸点不在图片上时,不移动图片。

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.cindy.picdrag.MainActivity">

    <ImageView
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:id="@+id/iv"
        android:src="@drawable/yy"/>
</LinearLayout>

线性布局里放了一张图片。图片默认位置在屏幕左上角。
MainActivity.java
定义ImageView iv//布局里的ImageView
View rootView;//屏幕根布局
int actionBarHeight; //表示demo图中蓝色部分的高度
int notifiHeight;// 表示demo图中通知栏的高度
ImageView moveIv; //表示拖动需要显示的ImageView
onCreate方法:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        rootView = getLayoutInflater().inflate(R.layout.activity_main,null);//获取根布局
        rootView.post(new Runnable() {
            @Override
            public void run() {
                if(getSupportActionBar()!=null){
                    //获取actionBar的高度
                    actionBarHeight = getSupportActionBar().getHeight();
                    //获取通知栏的高度
                    Rect rect = new Rect();
                    getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
                    notifiHeight = rect.top;
                    System.out.println("height:"+(actionBarHeight+notifiHeight));
                }else{
                    System.out.println("view has not a actionBar");
                }
            }
        });
        iv = (ImageView)findViewById(R.id.iv);
    }

android 图片上下居中 android怎么让图片移动_android_02


捕获触摸点的x,y坐标

//返回触摸点的x坐标
    private float getTouchXPoint(MotionEvent event,int pointIndex){
        return MotionEventCompat.getX(event, pointIndex);
    }
    //返回触摸点的y坐标
    private float getTouchYPoint(MotionEvent event,int pointIndex){
        return MotionEventCompat.getY(event, pointIndex);
    }

如上图,五个点从上到下命名为ABCDE.
需要判断触摸点是否包含在imageView中,如D点,此时拖动,图片会随着触摸点的移动而移动,如果触摸点是E点,则图片不动。
A点是坐标原点,上面的getTouchXPoint,getTouchYpoint坐标就是相对A点的坐标值。
actionBar和notifyBar的高度和就是AB的值。设该值为offsetHeight
获取图片初始位置:

LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)iv.getLayoutParams();
        int ivWidth = iv.getWidth();
        int ivHeight = iv.getHeight();
  showLog("左上角x: "+llp.leftMargin+" 左上角y: "+llp.topMargin);
        showLog("左下角x: "+llp.leftMargin+" 左下角y: "+(llp.topMargin+ivHeight));
        showLog("右上角x: "+(llp.leftMargin+ivWidth)+"右上角y: "+llp.topMargin);
        showLog("右下角x: "+(llp.leftMargin+ivWidth)+"右下角y: "+(llp.topMargin+ivHeight));

用 LinearLayout.LayoutParams获取的iv初始位置相对于B点。
这样就有一个问题:触摸点的原点是A点(0,0),而iv的原点是B点(0,243)。需要统一坐标系:触摸点的y值-offsetHeight后即可和iv的坐标系统一。
判断触摸点是否在iv范围内:

int relx = x;
 int rely = (int)getTouchYPoint(event,pointIndex)-offsetHeight;
 if((relx>llp.leftMargin)&&  (relx<llp.leftMargin+ivWidth)&&
                (rely>llp.topMargin)&&(rely<llp.topMargin+ivHeight)){
            return true;
        }else{
            return false;
        }

返回true表示触摸点在image中,返回false表示触摸点在image外。

复写onTouchEvent方法,实现拖动

@Override
    public boolean onTouchEvent(MotionEvent event) {
        int actionTag = MotionEventCompat.getActionMasked(event);
        int pointIndex = MotionEventCompat.getActionIndex(event);
        switch (actionTag){
            case MotionEvent.ACTION_DOWN:
                if(isPointInPic(event,pointIndex)){
                    moveIv = iv;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(moveIv!=null){
                    LinearLayout.LayoutParams llpm = (LinearLayout.LayoutParams)iv.getLayoutParams();
                    llpm.leftMargin = (int)(getTouchXPoint(event,pointIndex)-difX);  //左边距
                    llpm.topMargin = (int)(getTouchYPoint(event,pointIndex)-difY);//上边距
                    iv.setLayoutParams(llpm);
                }
                break;
            case MotionEvent.ACTION_UP:
                moveIv = null;
                break;
        }
        return super.onTouchEvent(event);
    }

MotionEvent.ACTION_DOWN:按下。此时需要判断触摸点是否在imageView内部。如果在内部,把iv赋值给moveIv.
MotionEvent.ACTION_MOVE:监听移动。当moveIv不为空时重置iv的位置,实现拖动。
MotionEvent.ACTION_UP:监听抬起。抬起时把moveIv置空。

int x = (int)getTouchXPoint(event,pointIndex);
 int y = (int)getTouchYPoint(event,pointIndex);
 //图片初始位置
 LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)iv.getLayoutParams();
difX = x-llp.leftMargin;//触摸点相对imageviwe的x偏移量
difY = y-llp.topMargin;//触摸点相对imageviwe的y偏移量

difX和difY是图上点D相对于点C的x,y偏移量。
因为imageView移动的位置是相对于点C而不是点D,所以MotionEvent.ACTION_MOVE事件中,imageView的位置参数需要把偏移量减掉。
完整的MainActivity如下

public class MainActivity extends AppCompatActivity {
    private ImageView iv;
    private View rootView;
    private int actionBarHeight = 0;
    private int notifiHeight;

    private ImageView moveIv;

    private float difX;
    private float difY;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        rootView = getLayoutInflater().inflate(R.layout.activity_main,null);//获取根布局
        rootView.post(new Runnable() {
            @Override
            public void run() {
                if(getSupportActionBar()!=null){
                    //获取actionBar的高度
                    actionBarHeight = getSupportActionBar().getHeight();
                    //获取通知栏的高度
                    Rect rect = new Rect();
                    getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
                    notifiHeight = rect.top;
                    System.out.println("height:"+(actionBarHeight+notifiHeight));
                }else{
                    System.out.println("view has not a actionBar");
                }
            }
        });
        iv = (ImageView)findViewById(R.id.iv);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int actionTag = MotionEventCompat.getActionMasked(event);
        int pointIndex = MotionEventCompat.getActionIndex(event);
        switch (actionTag){
            case MotionEvent.ACTION_DOWN:
                if(isPointInPic(event,pointIndex)){
                    moveIv = iv;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(moveIv!=null){
                    LinearLayout.LayoutParams llpm = (LinearLayout.LayoutParams)iv.getLayoutParams();
                    llpm.leftMargin = (int)(getTouchXPoint(event,pointIndex)-difX);  //左边距
                    llpm.topMargin = (int)(getTouchYPoint(event,pointIndex)-difY);//上边距
                    iv.setLayoutParams(llpm);
                }
                break;
            case MotionEvent.ACTION_UP:
                moveIv = null;
                break;
        }
        return super.onTouchEvent(event);
    }
    //返回触摸点的x坐标
    private float getTouchXPoint(MotionEvent event,int pointIndex){
        return MotionEventCompat.getX(event, pointIndex);
    }
    //返回触摸点的y坐标
    private float getTouchYPoint(MotionEvent event,int pointIndex){
        return MotionEventCompat.getY(event, pointIndex);
    }
    private boolean isPointInPic(MotionEvent event,int pointIndex){
        int x = (int)getTouchXPoint(event,pointIndex);
        int y = (int)getTouchYPoint(event,pointIndex);
        //图片初始位置
        LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)iv.getLayoutParams();
        int ivWidth = iv.getWidth();
        int ivHeight = iv.getHeight();
        int relx = x;
        int rely = (int)getTouchYPoint(event,pointIndex)-actionBarHeight-notifiHeight;
        //计算D点和C点的偏移
        difX = x-llp.leftMargin;
        difY = y-llp.topMargin;
        //判断点击的点是否在图片的范围内
        if((relx>llp.leftMargin)&&(relx<llp.leftMargin+ivWidth)&&
                (rely>llp.topMargin)&&(rely<llp.topMargin+ivHeight)){
            return true;
        }else{
            return false;
        }
    }
}