效果展示

%title插图%num
做Android自定义View开发,实现布局的滑动是必不可少的一项手艺。下面我为大家准备了五种移动布局的方法:

layout 法 CoordinatorLayout原理的简析
LayoutParams 法 CoordinatorLayout原理的简析
scrollTo/scrollBy
Scroller 类
ViewDragHelper 类 : ViewDragHelper 类
activity_main.xml布局文件

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:orientation=”vertical”
tools:context=”.MainActivity”>

<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width=”match_parent”
android:layout_height=”match_parent”>

<com.wust.SelfCoordinator.CanDragView
android:layout_width=”100dp”
android:layout_height=”100dp”
android:background=”#f00″/>
<TextView
android:layout_width=”100dp”
android:layout_height=”100dp”
android:background=”#0f0″
android:layout_marginTop=”200dp”/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

</LinearLayout>
这里面存在 CoordinatorLayout 这个布局,是因为我准备写 CoordinatorLayout 布局的教程的,Android滑动方式只是个小插曲,所以,布局文件可以不用按照我的写,仅供参考。

1、layout 法

自定义View的 java 代码

package com.wust.SelfCoordinator;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

/**
* ClassName: CanDragView <br/>
* Description: <br/>
* date: 2021/6/29 9:45<br/>
*
* @author yiqi<br />
* @QQ 1820762465
*/
public class CanDragView extends View {

int startX;
int startY;

public CanDragView(Context context) {
this(context,null);
}

public CanDragView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}

public CanDragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
{
startX =(int) event.getX();
startY =(int) event.getY();
}
break;
case MotionEvent.ACTION_MOVE:
{
int endX = (int) event.getX();
int endY = (int) event.getY();
int moveX = endX – startX;
int moveY = endY – startY;
System.out.println(“moveX ->” + moveX + “moveY ->” + moveY);
//移动布局的关键性代码
layout(getLeft()+moveX,getTop()+moveY,getRight()+moveX,getBottom()+moveY);
}
break;
}
return true;
}

}
2、LayoutParams 法

package com.wust.SelfCoordinator;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

/**
* ClassName: CanDragView <br/>
* Description: <br/>
* date: 2021/6/29 9:45<br/>
*
* @author yiqi<br />
* @QQ 1820762465
*/
public class CanDragView extends View {

int startX;
int startY;

public CanDragView(Context context) {
this(context,null);
}

public CanDragView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}

public CanDragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
{
startX =(int) event.getX();
startY =(int) event.getY();
}
break;
case MotionEvent.ACTION_MOVE:
{
int endX = (int) event.getX();
int endY = (int) event.getY();
int moveX = endX – startX;
int moveY = endY – startY;
System.out.println(“moveX ->” + moveX + “moveY ->” + moveY);
//移动布局的关键性代码,如果布局已经在 xml 文件中存在,你直接用 getLayoutParams() 获取参数信息就可以了,不要在重新 new
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) getLayoutParams();
params.leftMargin = getLeft()+moveX;
params.topMargin = getTop()+moveY;
setLayoutParams(params);
}
break;
}
return true;
}

}
3、scrollTo/scrollBy

package com.wust.SelfCoordinator;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

/**
* ClassName: CanDragView <br/>
* Description: <br/>
* date: 2021/6/29 9:45<br/>
*
* @author yiqi<br />
* @QQ 1820762465
*/
@SuppressLint(“AppCompatCustomView”)
public class CanDragView extends TextView {

int startX;
int startY;

public CanDragView(Context context) {
this(context,null);
}

public CanDragView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}

public CanDragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
{
startX =(int) event.getX();
startY =(int) event.getY();
}
break;
case MotionEvent.ACTION_MOVE:
{
int endX = (int) event.getX();
int endY = (int) event.getY();
int moveX = endX – startX;
int moveY = endY – startY;
System.out.println(“moveX ->” + moveX + “moveY ->” + moveY);
//移动布局的关键性代码,scrollTo/scrollBy 移动的是 View中的内容 ViewGroup中的子View
scrollTo(-(getLeft()+moveX),-(getTop()+moveY));
invalidate();
}
break;
}
return true;
}

}
需要注意的两点:

这个方法移动的 布局 的内容,不是自己
得加负号,大家自己尝试一下就明白了

%title插图%num
Scroller 类

原理大家可以参考这篇文章 : Scroller与computeScroll处理滑动

package com.wust.SelfCoordinator;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

/**
* ClassName: CanDragView <br/>
* Description: <br/>
* date: 2021/6/29 9:45<br/>
*
* @author yiqi<br />
* @QQ 1820762465
*/
@SuppressLint(“AppCompatCustomView”)
public class CanDragView extends TextView {

int startX;
int startY;
private Scroller scroller;
private int moveX;
private int moveY;

public CanDragView(Context context) {
this(context,null);
}

public CanDragView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}

public CanDragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//*步:创建 scroller 对象
scroller = new Scroller(context);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
{
startX =(int) event.getX();
startY =(int) event.getY();
}
break;
case MotionEvent.ACTION_MOVE:
{
int endX = (int) event.getX();
int endY = (int) event.getY();
moveX = endX – startX;
moveY = endY – startY;
System.out.println(“moveX ->” + moveX + “moveY ->” + moveY);
//移动布局的关键性代码,scrollTo/scrollBy 移动的是 View中的内容 ViewGroup中的子View
//第二步:开始滚动
scroller.startScroll(getLeft(),getTop(), moveX, moveY);
//这个不能少,因为这个会调用 computeScroll()
invalidate();
}
break;
}
return true;
}

@Override
public void computeScroll() {
//第三步:编写 computeScroll,反复矫正
if (scroller.computeScrollOffset()){
scrollTo(getLeft()+moveX,getTop()+moveY);
invalidate();
}
super.computeScroll();
}
}
这个方法也是移动内容,和 scrollTo / scrollBy 一样。

ViewDragHelper 类
————————————————