parent 的高度和宽度不是预期的
Height and Width of parent are not what is expected
我正在尝试创建一个应该生成垂直滑块的自定义渲染器。如果我在 tablet 模拟器上 运行 滑块的拇指拖动有效并且拇指开始完美滑动。完美检测尺寸。比我 运行 它在我的 phone 和哎呀那是什么。拇指突然不能正常工作了。问题出在放置 Thumb 的 parent 的宽度和高度上。在 table 模拟器上,我得到了预期的宽度和高度,但在我的 Phone 上,我得到了意外的值。
Android 上的尺寸不是以像素为单位吗?有什么我需要考虑的因素吗?
下面是自定义渲染器。问题出在这部分:
case MotionEventActions.Move:
if (touchedDown)
{
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Horizontal)
{
var newX = x - dX;
if (parent != null)
{
// The parent.Width isn't what I expect below
if (newX + Width > parent.Width) newX = (float)(parent.Width - Width);
if (newX < 0) newX = 0;
}
SetX(newX);
}
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Vertical)
{
var newY = y - dY;
if (parent != null)
{
// The parent.Height isn't what I expect below
if (newY + Height > parent.Height) newY = (float)(parent.Height - Height);
if (newY < 0) newY = 0;
}
SetY(newY);
}
}
break;
这是 DraggableViewRenderer 的完整源代码:
using Android.Content;
using Android.Views;
using TGB.Xamarin.Forms.TestApp.Droid.Renderers.Views;
using TGB.Xamarin.Forms.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using static TGB.Xamarin.Forms.Views.DraggableView;
using xam = global::Xamarin.Forms;
[assembly: ExportRenderer(typeof(DraggableView), typeof(DraggableViewRenderer))]
namespace TGB.Xamarin.Forms.TestApp.Droid.Renderers.Views
{
public class DraggableViewRenderer : VisualElementRenderer<xam.View>
{
float originalX;
float originalY;
float dX;
float dY;
bool firstTime = true;
bool touchedDown = false;
public DraggableViewRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<xam.View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
LongClick -= HandleLongClick;
}
if (e.NewElement != null)
{
LongClick += HandleLongClick;
var dragView = Element as DraggableView;
dragView.RestorePositionCommand = new Command(() =>
{
if (!firstTime)
{
SetX(originalX);
SetY(originalY);
}
});
}
}
private void HandleLongClick(object sender, LongClickEventArgs e)
{
var dragView = Element as DraggableView;
if (firstTime)
{
originalX = GetX();
originalY = GetY();
firstTime = false;
}
dragView.DragStarted();
touchedDown = true;
}
public override bool OnTouchEvent(MotionEvent e)
{
float x = e.RawX;
float y = e.RawY;
var dragView = Element as DraggableView;
var parent = dragView.Parent as xam.View;
switch (e.Action)
{
case MotionEventActions.Down:
if (dragView.DragMode == DragModes.Touch)
{
if (!touchedDown)
{
if (firstTime)
{
originalX = GetX();
originalY = GetY();
firstTime = false;
}
dragView.DragStarted();
}
touchedDown = true;
}
dX = x - this.GetX();
dY = y - this.GetY();
break;
case MotionEventActions.Move:
if (touchedDown)
{
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Horizontal)
{
var newX = x - dX;
if (parent != null)
{
if (newX + Width > parent.Width) newX = (float)(parent.Width - Width);
if (newX < 0) newX = 0;
}
SetX(newX);
}
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Vertical)
{
var newY = y - dY;
if (parent != null)
{
if (newY + Height > parent.Height) newY = (float)(parent.Height - Height);
if (newY < 0) newY = 0;
}
SetY(newY);
}
}
break;
case MotionEventActions.Up:
touchedDown = false;
DraggableViewDragEndedEventArgs args = new DraggableViewDragEndedEventArgs
{
X = GetX(),
Y = GetY()
};
dragView.DragEnded(args);
break;
case MotionEventActions.Cancel:
touchedDown = false;
break;
}
return base.OnTouchEvent(e);
}
public override bool OnInterceptTouchEvent(MotionEvent e)
{
BringToFront();
return true;
}
}
}
parent.width
是容器的宽度(以像素为单位)。它可以小于显示宽度。此外,如果容器与其尺寸重叠(例如,"android:width="1000dp"),则它可能比显示更大。您应该在此处添加布局。
要获得显示宽度,请参阅 How to get screen dimensions as pixels in Android。
好的,正如我所怀疑的那样,问题出在密度上。 Xamarin.Essentials 有解决办法。在您的代码中执行此操作:
var density = global::Xamarin.Essentials.DeviceDisplay.MainDisplayInfo.Density; // 2.625 in my case
将 parent.Width 和 parent.Height 与密度相乘,得到宽度(以像素为单位)
var width = parent.Width * density;
var height = parent.Height * density;
我正在尝试创建一个应该生成垂直滑块的自定义渲染器。如果我在 tablet 模拟器上 运行 滑块的拇指拖动有效并且拇指开始完美滑动。完美检测尺寸。比我 运行 它在我的 phone 和哎呀那是什么。拇指突然不能正常工作了。问题出在放置 Thumb 的 parent 的宽度和高度上。在 table 模拟器上,我得到了预期的宽度和高度,但在我的 Phone 上,我得到了意外的值。
Android 上的尺寸不是以像素为单位吗?有什么我需要考虑的因素吗?
下面是自定义渲染器。问题出在这部分:
case MotionEventActions.Move:
if (touchedDown)
{
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Horizontal)
{
var newX = x - dX;
if (parent != null)
{
// The parent.Width isn't what I expect below
if (newX + Width > parent.Width) newX = (float)(parent.Width - Width);
if (newX < 0) newX = 0;
}
SetX(newX);
}
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Vertical)
{
var newY = y - dY;
if (parent != null)
{
// The parent.Height isn't what I expect below
if (newY + Height > parent.Height) newY = (float)(parent.Height - Height);
if (newY < 0) newY = 0;
}
SetY(newY);
}
}
break;
这是 DraggableViewRenderer 的完整源代码:
using Android.Content;
using Android.Views;
using TGB.Xamarin.Forms.TestApp.Droid.Renderers.Views;
using TGB.Xamarin.Forms.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using static TGB.Xamarin.Forms.Views.DraggableView;
using xam = global::Xamarin.Forms;
[assembly: ExportRenderer(typeof(DraggableView), typeof(DraggableViewRenderer))]
namespace TGB.Xamarin.Forms.TestApp.Droid.Renderers.Views
{
public class DraggableViewRenderer : VisualElementRenderer<xam.View>
{
float originalX;
float originalY;
float dX;
float dY;
bool firstTime = true;
bool touchedDown = false;
public DraggableViewRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<xam.View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
LongClick -= HandleLongClick;
}
if (e.NewElement != null)
{
LongClick += HandleLongClick;
var dragView = Element as DraggableView;
dragView.RestorePositionCommand = new Command(() =>
{
if (!firstTime)
{
SetX(originalX);
SetY(originalY);
}
});
}
}
private void HandleLongClick(object sender, LongClickEventArgs e)
{
var dragView = Element as DraggableView;
if (firstTime)
{
originalX = GetX();
originalY = GetY();
firstTime = false;
}
dragView.DragStarted();
touchedDown = true;
}
public override bool OnTouchEvent(MotionEvent e)
{
float x = e.RawX;
float y = e.RawY;
var dragView = Element as DraggableView;
var parent = dragView.Parent as xam.View;
switch (e.Action)
{
case MotionEventActions.Down:
if (dragView.DragMode == DragModes.Touch)
{
if (!touchedDown)
{
if (firstTime)
{
originalX = GetX();
originalY = GetY();
firstTime = false;
}
dragView.DragStarted();
}
touchedDown = true;
}
dX = x - this.GetX();
dY = y - this.GetY();
break;
case MotionEventActions.Move:
if (touchedDown)
{
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Horizontal)
{
var newX = x - dX;
if (parent != null)
{
if (newX + Width > parent.Width) newX = (float)(parent.Width - Width);
if (newX < 0) newX = 0;
}
SetX(newX);
}
if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Vertical)
{
var newY = y - dY;
if (parent != null)
{
if (newY + Height > parent.Height) newY = (float)(parent.Height - Height);
if (newY < 0) newY = 0;
}
SetY(newY);
}
}
break;
case MotionEventActions.Up:
touchedDown = false;
DraggableViewDragEndedEventArgs args = new DraggableViewDragEndedEventArgs
{
X = GetX(),
Y = GetY()
};
dragView.DragEnded(args);
break;
case MotionEventActions.Cancel:
touchedDown = false;
break;
}
return base.OnTouchEvent(e);
}
public override bool OnInterceptTouchEvent(MotionEvent e)
{
BringToFront();
return true;
}
}
}
parent.width
是容器的宽度(以像素为单位)。它可以小于显示宽度。此外,如果容器与其尺寸重叠(例如,"android:width="1000dp"),则它可能比显示更大。您应该在此处添加布局。
要获得显示宽度,请参阅 How to get screen dimensions as pixels in Android。
好的,正如我所怀疑的那样,问题出在密度上。 Xamarin.Essentials 有解决办法。在您的代码中执行此操作:
var density = global::Xamarin.Essentials.DeviceDisplay.MainDisplayInfo.Density; // 2.625 in my case
将 parent.Width 和 parent.Height 与密度相乘,得到宽度(以像素为单位)
var width = parent.Width * density;
var height = parent.Height * density;