using System;
|
using Android.Content;
|
using Android.Views;
|
using Android.Views.Animations;
|
|
namespace Shared
|
{
|
/// <summary>
|
/// 音乐滑动视图
|
/// </summary>
|
public class MusicVerticalScrolViewLayout : ViewGroup
|
{
|
/// <summary>
|
/// 构造函数
|
/// </summary>
|
public MusicVerticalScrolViewLayout()
|
{
|
viewGroup = new AndroidScrolView11(Application.Activity, this);
|
var tempViewGroup = new Android.Widget.FrameLayout(Application.Activity);
|
//ScrollView这样的控件需要先有个容器,而且容器高宽不能设定,而是由容器里的子控件高度决定
|
viewGroup.AddView(tempViewGroup);
|
realViewGroup = new Android.Widget.FrameLayout(Application.Activity);
|
tempViewGroup.AddView(realViewGroup);
|
}
|
|
//这个方法检查过没有问题
|
/// <summary>
|
/// 添加子控件
|
/// </summary>
|
/// <param name="view">View.</param>
|
public override void AddChidren(View view)
|
{
|
base.AddChidren(view);
|
int height = 0;
|
foreach(View tempView in viewList){
|
if(height<tempView.Bottom)
|
{
|
height = tempView.Bottom;
|
}
|
}
|
realViewGroup.LayoutParameters.Height = height < viewGroup.LayoutParameters.Height ? viewGroup.LayoutParameters.Height+10 : height;
|
}
|
|
/// <summary>
|
/// 根据绝对坐标来确定当前选择了哪个控件
|
/// </summary>
|
/// <returns><c>true</c>, if range of view was ined, <c>false</c> otherwise.</returns>
|
/// <param name="view">View.</param>
|
/// <param name="point">Point.</param>
|
bool inRangeOfView(Android.Views.View view, Android.Graphics.Point point)
|
{
|
var location = new int[2];
|
view.GetLocationOnScreen(location);
|
int y = location[1];
|
if (point.Y < y || point.Y > (y + view.Height))
|
{
|
return false;
|
}
|
return true;
|
}
|
|
bool isSameZone (Android.Views.View view)
|
{
|
var location = new int [2];
|
view.GetLocationOnScreen (location);
|
int y = location [1];
|
if (y + view.Height / 2 < selectViewBeforeY || y > selectViewBeforeY + view.Height / 2) {
|
return false;
|
}
|
return true;
|
}
|
|
/// <summary>
|
/// 根据点击位置找出点击到的视图
|
/// </summary>
|
/// <returns>The view of point.</returns>
|
/// <param name="point">Point.</param>
|
/// <param name="view">Uiview.</param>
|
Android.Views.View replaceViewOfPoint(Android.Views.View view, Android.Graphics.Point point)
|
{
|
//第一个是背景图
|
for (int i = realViewGroup.ChildCount - 1; 0 <= i; i--)
|
{
|
var tempView = realViewGroup.GetChildAt(i);
|
if (tempView != view)
|
{
|
if (inRangeOfView(tempView, point))
|
{
|
return tempView;
|
}
|
}
|
}
|
return null;
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
public Action<View, View> ReplaceChanged;
|
/// <summary>
|
/// 长按事件
|
/// </summary>
|
public Action<View> LongPressAction;
|
|
/// <summary>
|
/// 根据点击位置找出点击到的视图
|
/// </summary>
|
/// <returns>返回点击到的视图</returns>
|
/// <param name="point">当前点击位置</param>
|
Android.Views.View selectedViewByPoint(Android.Graphics.Point point)
|
{
|
//第一个是背景图
|
for (int i = realViewGroup.ChildCount - 1; 0 <= i; i--)
|
{
|
var tempView = realViewGroup.GetChildAt(i);
|
{
|
if (inRangeOfView(tempView, point))
|
{
|
return tempView;
|
}
|
}
|
}
|
return null;
|
}
|
/// <summary>
|
/// 当前选中按键的初始点
|
/// </summary>
|
Android.Graphics.Point originPressPoint;
|
|
/// <summary>
|
/// 当前选中的视图起点
|
/// </summary>
|
Android.Graphics.Point selectedViewPoint;
|
|
/// <summary>
|
/// 当前选中的视图
|
/// </summary>
|
Android.Views.View selectedAndroidView;
|
/// <summary>
|
/// 准备交换位置的视图
|
/// </summary>
|
Android.Views.View replaceAndroidView;
|
|
/// <summary>
|
/// 获取当前View的中心点
|
/// </summary>
|
/// <returns>The point.</returns>
|
/// <param name="view">View.</param>
|
Android.Graphics.Point centerPoint(Android.Views.View view)
|
{
|
int[] location = new int[2];
|
view.GetLocationOnScreen(location);
|
int x = location[0];
|
int y = location[1];
|
x += view.Width / 2;
|
y += view.Height / 2;
|
return new Android.Graphics.Point(x, y);
|
}
|
|
|
float selectViewBeforeY;
|
/// <summary>
|
/// 点击开始的事件
|
/// </summary>
|
/// <param name="e">E.</param>
|
internal void TouchEventDown(MotionEvent e){
|
//找出当前点击位置的视图
|
selectedAndroidView = selectedViewByPoint(new Android.Graphics.Point((int)e.RawX, (int)e.RawY));
|
if (selectedAndroidView == null)
|
{
|
return ;
|
}
|
selectedAndroidView.BringToFront();
|
var location = new int [2];
|
selectedAndroidView.GetLocationOnScreen (location);
|
selectViewBeforeY = location [1];
|
originPressPoint = new Android.Graphics.Point((int)e.RawX, (int)e.RawY);
|
selectedViewPoint = new Android.Graphics.Point((int)selectedAndroidView.GetX(), (int)selectedAndroidView.GetY());
|
isFirst = true;
|
}
|
/// <summary>
|
/// 点击事件移动
|
/// </summary>
|
/// <param name="e">E.</param>
|
internal void TouchEventMove(MotionEvent e)
|
{
|
if (selectedAndroidView == null)
|
{
|
return;
|
}
|
//selectedAndroidView.SetX(selectedViewPoint.X + e.RawX - originPressPoint.X);
|
selectedAndroidView.SetY(selectedViewPoint.Y + e.RawY - originPressPoint.Y);
|
//获取当前视图进入了哪个视图的区域
|
replaceAndroidView = replaceViewOfPoint(selectedAndroidView, centerPoint(selectedAndroidView));
|
if (replaceAndroidView != null)
|
{
|
if (!isFirst)
|
{
|
return;
|
}
|
isFirst = false;
|
if (replaceAndroidView == null)
|
{
|
return;
|
}
|
replaceAndroidView.ClearAnimation();
|
/** 设置缩放动画 */
|
replaceAndroidView.Animation = new AlphaAnimation(1.0f, .8f);
|
replaceAndroidView.Animation.Duration = 1000;
|
replaceAndroidView.Animation.StartNow();
|
}
|
}
|
/// <summary>
|
/// 点击事件弹起
|
/// </summary>
|
/// <param name="e">E.</param>
|
internal void TouchEventUp(MotionEvent e)
|
{
|
if (selectedAndroidView == null)
|
{
|
return;
|
}
|
View selectedView = null;
|
foreach (View view in viewList)
|
{
|
if (view.AndroidView == selectedAndroidView)
|
{
|
selectedView = view;
|
break;
|
}
|
}
|
|
//selectedAndroidView.SetX(selectedViewPoint.X);
|
|
|
if(isSameZone(selectedAndroidView))
|
{
|
selectedAndroidView.SetY (selectedViewPoint.Y);
|
return;
|
}
|
selectedAndroidView.SetY (selectedViewPoint.Y);
|
|
|
if (replaceAndroidView == null)
|
{
|
if (LongPressAction != null)
|
{
|
LongPressAction(selectedView);
|
}
|
return;
|
}
|
|
View replaceView = null;
|
foreach (View view in viewList)
|
{
|
if (view.AndroidView == replaceAndroidView)
|
{
|
replaceView = view;
|
break;
|
}
|
}
|
if (ReplaceChanged != null)
|
{
|
ReplaceChanged(replaceView, selectedView);
|
}
|
}
|
|
/// <summary>
|
/// 给当前选择中的控件个动画缩小的效果
|
/// </summary>
|
internal void scaleSelectedAndroidView()
|
{
|
if (selectedAndroidView == null)
|
{
|
return;
|
}
|
selectedAndroidView.ClearAnimation();
|
/** 设置缩放动画 */
|
selectedAndroidView.Animation = new AlphaAnimation(1.0f, 0.8f);
|
selectedAndroidView.Animation.Duration = 1000;
|
selectedAndroidView.Animation.StartNow();
|
}
|
|
/// <summary>
|
/// 是否第一次加载
|
/// </summary>
|
bool isFirst;
|
|
/// <summary>
|
/// 竖直方向滑动控件
|
/// </summary>
|
internal class AndroidScrolView11 : Android.Widget.ScrollView, GestureDetector.IOnGestureListener
|
{
|
MusicVerticalScrolViewLayout _view;
|
/// <summary>
|
/// 是否长按
|
/// </summary>
|
bool isLongPress;
|
GestureDetector mGesture;
|
|
|
/// <summary>
|
/// 构造函数
|
/// </summary>
|
/// <param name="context">Context.</param>
|
/// <param name="view">View.</param>
|
public AndroidScrolView11(Context context, MusicVerticalScrolViewLayout view)
|
: base(context)
|
{
|
_view = view;
|
VerticalScrollBarEnabled = false;
|
mGesture = new GestureDetector(context, this) { IsLongpressEnabled = true };
|
}
|
|
/// <summary>
|
/// 重写点击事件
|
/// </summary>
|
/// <returns><c>true</c>, if touch event was oned, <c>false</c> otherwise.</returns>
|
/// <param name="e">E.</param>
|
public override bool OnTouchEvent(MotionEvent e)
|
{
|
//处理长按的事件
|
if (isLongPress)
|
{
|
switch (e.Action)
|
{
|
case MotionEventActions.Move:
|
_view.TouchEventMove(e);
|
break;
|
case MotionEventActions.Up:
|
_view.TouchEventUp(e);
|
break;
|
}
|
return true;
|
}
|
|
return base.OnTouchEvent(e);
|
}
|
|
//是否是活动状态
|
bool isLive()
|
{
|
return Enabled && Visibility == ViewStates.Visible && 0 < Alpha;
|
}
|
|
public override bool OnInterceptTouchEvent(MotionEvent ev)
|
{
|
if (!isLive())
|
{
|
return false;
|
}
|
mGesture.OnTouchEvent(ev);
|
//如果是长按,就拦截事件,后面的事件是由自己的TouchEvent处理,子控件会收到取消事件,如果是快速滑动,事件也是自己处理
|
if (isLongPress)
|
{
|
return true;
|
}
|
//如果是滑动这里也会返回True
|
return base.OnInterceptTouchEvent(ev);
|
}
|
|
/// <summary>
|
/// 设置所有父视图禁止拦截事件
|
/// </summary>
|
/// <param name="b">如果设置True表示不要拦截,如果设置为False表示可以拦截</param>
|
void requestParentDisallowInterceptTouchEvent(bool b)
|
{
|
var tempParent = Parent;
|
while (tempParent != null)
|
{ //告诉父类不要拦截这个视图的事件
|
tempParent.RequestDisallowInterceptTouchEvent(b);
|
tempParent = tempParent.Parent;
|
}
|
}
|
|
public bool OnDown(MotionEvent e)
|
{
|
isLongPress = false;
|
_view.TouchEventDown(e);
|
requestParentDisallowInterceptTouchEvent(true);
|
return false;
|
}
|
|
public bool OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
|
{
|
//迅速滑动,并松开
|
Shared.HDLUtils.WriteLine($"OnFling随便一划,坐标变化为X:{velocityX},Y:{velocityY}");
|
return false;
|
}
|
|
public void OnLongPress(MotionEvent e)
|
{
|
isLongPress = true;
|
_view.scaleSelectedAndroidView();
|
Shared.HDLUtils.WriteLine("长按不放");
|
}
|
|
public bool OnScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
|
{
|
Shared.HDLUtils.WriteLine("OnScroll:在屏幕上滑动");
|
return false;
|
}
|
|
public void OnShowPress(MotionEvent e)
|
{
|
Shared.HDLUtils.WriteLine("OnShowPress:手指按下一段时间,还没到长按");
|
}
|
|
public bool OnSingleTapUp(MotionEvent e)
|
{
|
requestParentDisallowInterceptTouchEvent(false);
|
Shared.HDLUtils.WriteLine("OnSingleTapUp:手指弹起");
|
return false;
|
}
|
}
|
}
|
|
}
|