根据开始拖动和结束拖动之间的距离调整视图大小
Resizing a view based on the distance between start drag and end drag
我正在开发一个项目,其中有一个视图,单击后会实例化一个 class,将视图传递给构造函数,构造函数会在视图上创建 4 个锚点。这是使用以下方法完成的:
customView = new CustomView(MainActivity.this, viewCounter,
customView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Resizer resizer = new Resizer(MainActivity.this, MainActivity.this, container, customView, lblStatus);
}
});
缩放器class如下:
public Resizer(Context context, AppCompatActivity activity, ViewGroup container, ViewGroup viewToBeResized, TextView lblStatus)
{
this.context = context;
this.activity = activity;
this.container = container;
this.viewToBeResized = viewToBeResized;
this.lblStatus = lblStatus;
createAnchorPoints();
}
private void createAnchorPoints()
{
Drawable circle = ContextCompat.getDrawable(context, R.drawable.anchor);
int circleSize = dpToPx(CIRCLE_SIZE_DP);
Anchor topLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_LEFT, lblStatus);
topLeftAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams topLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
viewToBeResized.addView(topLeftAnchor, topLeftParms);
Anchor topRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_RIGHT, lblStatus);
topRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams topRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
topRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
topRightParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
viewToBeResized.addView(topRightAnchor, topRightParms);
Anchor bottomLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
bottomLeftAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomLeftAnchor, bottomLeftParms);
Anchor bottomRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
bottomRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomRightAnchor, bottomRightParms);
}
在每个角落创建的锚点 class 中,使用了触摸侦听器。我想要做的是当用户拖动锚点视图时,传递到锚点中的主视图将按照用户拖动的方向调整大小。
下面是我的触摸监听器
public class AnchorTouchListener implements View.OnTouchListener
{
private int _xDelta;
private int _yDelta;
private View viewToResize;
private TextView lblStatus;
private Anchor.ResizeMode resizeMode;
public AnchorTouchListener(View viewToResize, TextView lblStatus, Anchor.ResizeMode resizeMode)
{
this.viewToResize = viewToResize;
this.lblStatus = lblStatus;
this.resizeMode = resizeMode;
}
@Override
public boolean onTouch(View view, MotionEvent event)
{
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
Log.d("Anchor", "Updating X & Y");
int diff = 0;
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
lblStatus.setText("Moving down");
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
lblStatus.setText("Drag finished");
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
lblStatus.setText("Moving around");
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = _xDelta - X;
layoutParams.bottomMargin = _yDelta - Y;
view.setLayoutParams(layoutParams);
//viewToResize.animate().scaleX(0.6f);
if (resizeMode == Anchor.ResizeMode.BOTTOM_RIGHT)
{
diff = diff - X - _xDelta;
Log.d("Anchor Touch", "Diff: " + diff);
if (diff > 0)
{
((RelativeLayout.LayoutParams) viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width + Math.abs(diff);
}
else
{
((RelativeLayout.LayoutParams)viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width - Math.abs(diff);
}
}
break;
}
return true;
}
}
它有点工作,除了它不能与锚点一起平滑移动,正在调整大小的视图似乎比被拖动的视图增长得更快,并且在调整大小和收缩时非常不稳定。
是否有更好的方法来实现我想要实现的目标,或者任何人都可以看到我可能做错了什么。
更新
添加了视频以显示我正在努力实现的目标以及问题所在。
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
在您的 AnchorTouchListener class 上面的代码行中,您正在获取之前创建的视图端点的参数。
获取正确的 LayourParams 应该可以解决问题。
由于锚点是用RelativeLayout
定位的,因此无需编写代码来移动锚点。只需调整灰色框的大小,锚点就会在布局时正确定位。可以通过捕获指针放置的初始条件和框的初始大小来确定灰色框的大小,以实现以下。
我只实现了右下角的锚点,我对你的实现进行了一些改动,但这个概念对你的代码和其他锚点仍然有效。
AnchorTouchListener.java
public class AnchorTouchListener implements View.OnTouchListener {
private int _xDelta;
private int _yDelta;
private View viewToResize;
private TextView lblStatus;
// private Anchor.ResizeMode resizeMode;
public AnchorTouchListener(View viewToResize, TextView lblStatus/*, Anchor.ResizeMode resizeMode*/) {
this.viewToResize = viewToResize;
this.lblStatus = lblStatus;
// this.resizeMode = resizeMode;
}
private int initialHeight;
private int initialWidth;
private int initialX;
private int initialY;
@Override
public boolean onTouch(View view, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
Log.d("Anchor", "Updating X & Y");
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
lblStatus.setText("Action down");
// Capture initial conditions of the view to resize.
initialHeight = viewToResize.getHeight();
initialWidth = viewToResize.getWidth();
// Capture initial touch point.
initialX = X;
initialY = Y;
break;
case MotionEvent.ACTION_UP:
lblStatus.setText("Drag finished");
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
lblStatus.setText("Moving around");
RelativeLayout.LayoutParams lp =
(RelativeLayout.LayoutParams) viewToResize.getLayoutParams();
// Compute how far we have moved in the X/Y directions.
_xDelta = X - initialX;
_yDelta = Y - initialY;
// Adjust the size of the targeted view. Note that we don't have to position
// the resize handle since it will be positioned correctly due to the layout.
lp.width = initialWidth + _xDelta;
lp.height = initialHeight + _yDelta;
viewToResize.setLayoutParams(lp);
break;
}
return true;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Drawable circle = ContextCompat.getDrawable(this, R.drawable.circle);
ImageView imageView = new ImageView(this);
imageView.setImageDrawable(circle);
int circleSize = dpToPx(CIRCLE_SIZE_DP);
RelativeLayout viewToBeResized = findViewById(R.id.customView);
ImageView bottomRightAnchor = new ImageView(this);
bottomRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomRightParms =
new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomRightAnchor, bottomRightParms);
bottomRightAnchor.setOnTouchListener(
new AnchorTouchListener(viewToBeResized, ((TextView) findViewById(R.id.status))));
}
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density);
}
private static final int CIRCLE_SIZE_DP = 20;
}
activity_main.xml
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:id="@+id/customView"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="@android:color/holo_green_light" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
tools:text="Status"
android:layout_height="wrap_content" />
</RelativeLayout>
我正在开发一个项目,其中有一个视图,单击后会实例化一个 class,将视图传递给构造函数,构造函数会在视图上创建 4 个锚点。这是使用以下方法完成的:
customView = new CustomView(MainActivity.this, viewCounter,
customView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Resizer resizer = new Resizer(MainActivity.this, MainActivity.this, container, customView, lblStatus);
}
});
缩放器class如下:
public Resizer(Context context, AppCompatActivity activity, ViewGroup container, ViewGroup viewToBeResized, TextView lblStatus)
{
this.context = context;
this.activity = activity;
this.container = container;
this.viewToBeResized = viewToBeResized;
this.lblStatus = lblStatus;
createAnchorPoints();
}
private void createAnchorPoints()
{
Drawable circle = ContextCompat.getDrawable(context, R.drawable.anchor);
int circleSize = dpToPx(CIRCLE_SIZE_DP);
Anchor topLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_LEFT, lblStatus);
topLeftAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams topLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
viewToBeResized.addView(topLeftAnchor, topLeftParms);
Anchor topRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_RIGHT, lblStatus);
topRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams topRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
topRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
topRightParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
viewToBeResized.addView(topRightAnchor, topRightParms);
Anchor bottomLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
bottomLeftAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomLeftAnchor, bottomLeftParms);
Anchor bottomRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
bottomRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomRightAnchor, bottomRightParms);
}
在每个角落创建的锚点 class 中,使用了触摸侦听器。我想要做的是当用户拖动锚点视图时,传递到锚点中的主视图将按照用户拖动的方向调整大小。
下面是我的触摸监听器
public class AnchorTouchListener implements View.OnTouchListener
{
private int _xDelta;
private int _yDelta;
private View viewToResize;
private TextView lblStatus;
private Anchor.ResizeMode resizeMode;
public AnchorTouchListener(View viewToResize, TextView lblStatus, Anchor.ResizeMode resizeMode)
{
this.viewToResize = viewToResize;
this.lblStatus = lblStatus;
this.resizeMode = resizeMode;
}
@Override
public boolean onTouch(View view, MotionEvent event)
{
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
Log.d("Anchor", "Updating X & Y");
int diff = 0;
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
lblStatus.setText("Moving down");
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
lblStatus.setText("Drag finished");
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
lblStatus.setText("Moving around");
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = _xDelta - X;
layoutParams.bottomMargin = _yDelta - Y;
view.setLayoutParams(layoutParams);
//viewToResize.animate().scaleX(0.6f);
if (resizeMode == Anchor.ResizeMode.BOTTOM_RIGHT)
{
diff = diff - X - _xDelta;
Log.d("Anchor Touch", "Diff: " + diff);
if (diff > 0)
{
((RelativeLayout.LayoutParams) viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width + Math.abs(diff);
}
else
{
((RelativeLayout.LayoutParams)viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width - Math.abs(diff);
}
}
break;
}
return true;
}
}
它有点工作,除了它不能与锚点一起平滑移动,正在调整大小的视图似乎比被拖动的视图增长得更快,并且在调整大小和收缩时非常不稳定。
是否有更好的方法来实现我想要实现的目标,或者任何人都可以看到我可能做错了什么。
更新
添加了视频以显示我正在努力实现的目标以及问题所在。
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
在您的 AnchorTouchListener class 上面的代码行中,您正在获取之前创建的视图端点的参数。
获取正确的 LayourParams 应该可以解决问题。
由于锚点是用RelativeLayout
定位的,因此无需编写代码来移动锚点。只需调整灰色框的大小,锚点就会在布局时正确定位。可以通过捕获指针放置的初始条件和框的初始大小来确定灰色框的大小,以实现以下。
我只实现了右下角的锚点,我对你的实现进行了一些改动,但这个概念对你的代码和其他锚点仍然有效。
AnchorTouchListener.java
public class AnchorTouchListener implements View.OnTouchListener {
private int _xDelta;
private int _yDelta;
private View viewToResize;
private TextView lblStatus;
// private Anchor.ResizeMode resizeMode;
public AnchorTouchListener(View viewToResize, TextView lblStatus/*, Anchor.ResizeMode resizeMode*/) {
this.viewToResize = viewToResize;
this.lblStatus = lblStatus;
// this.resizeMode = resizeMode;
}
private int initialHeight;
private int initialWidth;
private int initialX;
private int initialY;
@Override
public boolean onTouch(View view, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
Log.d("Anchor", "Updating X & Y");
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
lblStatus.setText("Action down");
// Capture initial conditions of the view to resize.
initialHeight = viewToResize.getHeight();
initialWidth = viewToResize.getWidth();
// Capture initial touch point.
initialX = X;
initialY = Y;
break;
case MotionEvent.ACTION_UP:
lblStatus.setText("Drag finished");
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
lblStatus.setText("Moving around");
RelativeLayout.LayoutParams lp =
(RelativeLayout.LayoutParams) viewToResize.getLayoutParams();
// Compute how far we have moved in the X/Y directions.
_xDelta = X - initialX;
_yDelta = Y - initialY;
// Adjust the size of the targeted view. Note that we don't have to position
// the resize handle since it will be positioned correctly due to the layout.
lp.width = initialWidth + _xDelta;
lp.height = initialHeight + _yDelta;
viewToResize.setLayoutParams(lp);
break;
}
return true;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Drawable circle = ContextCompat.getDrawable(this, R.drawable.circle);
ImageView imageView = new ImageView(this);
imageView.setImageDrawable(circle);
int circleSize = dpToPx(CIRCLE_SIZE_DP);
RelativeLayout viewToBeResized = findViewById(R.id.customView);
ImageView bottomRightAnchor = new ImageView(this);
bottomRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomRightParms =
new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomRightAnchor, bottomRightParms);
bottomRightAnchor.setOnTouchListener(
new AnchorTouchListener(viewToBeResized, ((TextView) findViewById(R.id.status))));
}
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density);
}
private static final int CIRCLE_SIZE_DP = 20;
}
activity_main.xml
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:id="@+id/customView"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="@android:color/holo_green_light" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
tools:text="Status"
android:layout_height="wrap_content" />
</RelativeLayout>