using System;
using Android.Widget;
using Android.Content;
using Android.Views;
using Android.Util;
using Android.Runtime;
using Android.Views.Animations;
|
using Android.Graphics.Drawables;
|
|
namespace Shared
{
|
|
// 存在问题,下拉后不松开手改为上拉,会拦截MotionEventActions.Up事件,导致触发不了刷新
|
|
//VerticalRefreshScrolViewLayout 带下拉刷新
|
/// <summary>
/// 位置布局
/// </summary>
public class VerticalRefreshScrolViewLayout : ViewGroup
{
public Action BeginHeaderRefreshingAction;
|
//public Action beginFooterRefreshingAction;
|
//private LinearLayout mainLayout;
|
|
private MyLoadingHorizontal mHeaderLoadingView;//下拉刷新头部View
|
//private MyLoadingHorizontal mFooterLoadingView;//上拉加载底部View
|
|
/// <summary>
/// 构造函数
/// </summary>
public VerticalRefreshScrolViewLayout()
{
viewGroup = new AndroidRefreshScrolView(Application.Activity, null);
|
(viewGroup as AndroidRefreshScrolView).AlreadyToTopAction += () =>
|
{
|
ShowHeaderLoadingView();
|
};
|
|
(viewGroup as AndroidRefreshScrolView).AlreadyToTopUpAction += () =>
|
{
|
ShowHeaderAnimationBeginToRefresh();
|
};
|
|
mHeaderLoadingView = new MyLoadingHorizontal(Application.Activity);
|
HideHeaderLoadingView();
|
realViewGroup = new AndroidLinearLayout(Application.Activity, this);
(realViewGroup as AndroidLinearLayout).Orientation = Orientation.Vertical;
|
viewGroup.AddView(realViewGroup);
|
realViewGroup.AddView(mHeaderLoadingView);
|
|
_isCanHeaderRefresh = true;
|
|
}
|
|
|
|
|
|
/// <summary>
/// 视图宽度
/// </summary>
/// <value>The width.</value>
public override int Width
{
get
{
return base.Width;
}
set
{
base.Width = value;
if (!IsCanRefresh)
{
return;
}
var layoutParameters = realViewGroup.LayoutParameters;
layoutParameters.Width = Width;
realViewGroup.LayoutParameters = layoutParameters;
}
}
/// <summary>
/// 视图高度
/// </summary>
/// <value>The height.</value>
public override int Height
{
get
{
return base.Height;
}
set
{
base.Height = value;
if (!IsCanRefresh)
{
return;
}
var layoutParameters = realViewGroup.LayoutParameters;
layoutParameters.Height = Height;
realViewGroup.LayoutParameters = layoutParameters;
}
}
/// <summary>
/// 是否允许滑动
/// </summary>
/// <value><c>true</c> if scroll enabled; otherwise, <c>false</c>.</value>
public bool ScrollEnabled
{
get
{
return (viewGroup as AndroidScrolView).ScrollEnable;
}
set
{
(viewGroup as AndroidScrolView).ScrollEnable = value;
}
}
/// <summary>
/// 是否正在滑动
/// </summary>
/// <value><c>true</c> if decelerating; otherwise, <c>false</c>.</value>
public bool Decelerating
{
get
{
return false;
}
}
|
|
//***************************下拉刷新***************************
|
private void ShowHeaderLoadingView()
|
{
|
if (!IsCanHeaderRefresh) return;
|
|
if (IsHeaderRefreshing) return;
|
|
mHeaderLoadingView.HideProgress();
|
SetHeaderLoadingViewText(_mHeaderReadyRefreshText);
|
|
mHeaderLoadingView.Visibility = ViewStates.Visible;
|
|
|
//(viewGroup as AndroidRefreshScrolView).showHeader();
|
//showHeader();
|
|
}
|
|
private void ShowHeaderAnimationBeginToRefresh()
|
{
|
|
if (!IsCanHeaderRefresh) return;
|
|
|
if (!IsHeaderRefreshing)
|
{
|
mHeaderLoadingView.ShowProgress();
|
SetHeaderLoadingViewText(_mHeaderRefreshingText);
|
|
if (mHeaderLoadingView.Animation == null)
|
{
|
//缩放动画
|
mHeaderLoadingView.Animation = new ScaleAnimation(
|
1.0f, 1.2f, 1.0f, 1.2f,
|
Dimension.RelativeToSelf, 0.5f,
|
Dimension.RelativeToSelf, 0.5f);
|
mHeaderLoadingView.Animation.Duration = 300;
|
|
}
|
|
mHeaderLoadingView.Animation.Reset();
|
mHeaderLoadingView.Animation.StartNow();
|
//开始刷新
|
IsHeaderRefreshing = true;
|
BeginHeaderRefreshingAction?.Invoke();
|
}
|
}
|
|
private void SetHeaderLoadingViewText(string mes)
|
{
|
mHeaderLoadingView.textView.Text = mes;
|
}
|
|
|
private void HideHeaderLoadingView()
|
{
|
|
mHeaderLoadingView.Visibility = ViewStates.Gone;
|
|
//(viewGroup as AndroidRefreshScrolView).hideHeader();
|
//hideHeader();
|
|
|
}
|
|
|
|
string _mHeaderRefreshingText = "正在刷新...";
|
public string MHeaderRefreshingText
|
{
|
get
{
return _mHeaderRefreshingText;
}
|
set
|
{
|
_mHeaderRefreshingText = value;
|
}
|
}
|
|
string _mHeaderReadyRefreshText = "松开立即刷新";
|
public string MHeaderReadyRefreshText
|
{
|
get
{
return _mHeaderReadyRefreshText;
}
|
set
|
{
|
_mHeaderReadyRefreshText = value;
|
}
|
}
|
|
|
|
|
/// <summary>
/// 是否支持下拉刷新
/// </summary>
|
bool _isCanHeaderRefresh;
|
public bool IsCanHeaderRefresh
|
{
|
get
{
return _isCanHeaderRefresh;
}
|
set
|
{
|
_isCanHeaderRefresh = value;
|
}
|
}
|
|
/// <summary>
/// 是否正在下拉刷新
/// </summary>
|
bool _isHeaderRefreshing;
|
public bool IsHeaderRefreshing {
|
get
{
return _isHeaderRefreshing;
}
|
set
|
{
|
_isHeaderRefreshing = value;
|
}
|
}
|
|
|
///// <summary>
///// 启用或者关闭下拉刷新
///// </summary>
|
//public void openHeaderRefresh(bool bOpen)
|
//{
|
|
//}
|
|
/// <summary>
/// 头开始刷新
/// </summary>
|
public void BeginHeaderRefreshing()
|
{
|
if (!IsCanHeaderRefresh) return;
|
|
|
if (!IsHeaderRefreshing)
|
{
|
|
ShowHeaderLoadingView();
|
|
//mHeaderLoadingView.Visibility = ViewStates.Visible;
|
ShowHeaderAnimationBeginToRefresh();
|
|
}
|
}
|
|
/// <summary>
/// 头结束刷新
/// </summary>
|
public void EndHeaderRefreshing()
|
{
|
if (!IsCanHeaderRefresh) return;
|
|
if (IsHeaderRefreshing)
|
{
|
HideHeaderLoadingView();
|
IsHeaderRefreshing = false;
|
}
|
}
|
|
|
//public void showHeader()
|
//{
|
|
// mHeaderLoadingView.SetPadding(0, 0, 0, 0);
|
//}
|
|
//public void hideHeader()
|
//{
|
// mHeaderLoadingView.SetPadding(0, 0, 0, -100);
|
//}
|
|
|
////***************************上拉加载***************************
|
//string _mFooterRefreshText = "正在加载...";
|
//public string mFooterRefreshText
|
//{
|
// get
|
// {
|
// return _mFooterRefreshText;
|
// }
|
// set
|
// {
|
// _mFooterRefreshText = value;
|
// }
|
//}
|
|
///// <summary>
|
///// 是否支持 上拉加载
|
///// </summary>
|
//bool _isCanFooterRefresh;
|
//public bool IsCanFooterRefresh
|
//{
|
// get
|
// {
|
// return _isCanFooterRefresh;
|
// }
|
// set
|
// {
|
// _isCanFooterRefresh = value;
|
// }
|
//}
|
|
///// <summary>
|
///// 是否正在上拉加载
|
///// </summary>
|
//bool _isFooterRefreshing;
|
//public bool IsFooterRefreshing
|
//{
|
// get
|
// {
|
// return _isFooterRefreshing;
|
// }
|
// set
|
// {
|
// _isFooterRefreshing = value;
|
// }
|
//}
|
|
|
///// <summary>
|
///// 底部 开始上拉加载
|
///// </summary>
|
//public void beginFooterRefreshing()
|
//{
|
// if (!IsCanFooterRefresh) return;
|
|
// if (!IsFooterRefreshing)
|
// {
|
|
// mFooterLoadingView.Start(mHeaderRefreshText);
|
// IsFooterRefreshing = true;
|
// beginFooterRefreshingAction?.Invoke();
|
// }
|
//}
|
|
///// <summary>
|
///// 底部 结束上拉加载
|
///// </summary>
|
//public void endFooterRefreshing()
|
//{
|
// if (!IsCanFooterRefresh) return;
|
|
// if (IsFooterRefreshing)
|
// {
|
// mFooterLoadingView.Hide();
|
// IsFooterRefreshing = false;
|
// }
|
//}
|
|
|
|
|
|
|
}
/// <summary>
/// 竖直方向滑动控件
/// </summary>
class AndroidRefreshScrolView : Android.Widget.ScrollView
{
/// <summary>
/// 是否允许滑动
/// </summary>
public bool ScrollEnable = true;
|
|
public Action AlreadyToTopAction;
|
public Action AlreadyToTopUpAction;
|
public Action AlreadyToBottomAction;
|
|
//Scroller mScroller;
//public void showHeader() {
|
|
// this.SetPadding(0, 0, 0, 0);
|
// ////mScroller.
|
// //mScroller.StartScroll(0, 0, 0, 0, 400);
|
|
// //// trigger computeScroll
|
// //Invalidate();
|
//}
|
|
//public void hideHeader()
|
//{
|
// this.SetPadding(0, -50, 0, 0);
|
|
// ////mScroller.
|
// //mScroller.StartScroll(0, 40, 0, -40, 400);
|
|
// //// trigger computeScroll
|
// //Invalidate();
|
//}
View _view;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="context">Context.</param>
/// <param name="view">View.</param>
public AndroidRefreshScrolView(Context context, View view)
: base(context)
{
_view = view;
VerticalScrollBarEnabled = true;
//mScroller = new Scroller(context, new DecelerateInterpolator());
}
|
|
|
bool bAlreadyToTop;
public override bool DispatchTouchEvent(MotionEvent e)
|
{
|
//System.Console.WriteLine($"{GetType()} Height->{Height} Width->{Width} DispatchTouchEvent->{e.Action}");
|
if (e.Action == MotionEventActions.Down)
|
{
//还原允许拦截事件
|
RequestDisallowInterceptTouchEvent(false);
}
|
return base.DispatchTouchEvent(e);
|
}
|
|
float mLastX, mLastY ;
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
//System.Console.WriteLine($"{GetType()} Height->{Height} Width->{Width} OnInterceptTouchEvent->{ev.Action}");
|
|
if (!ScrollEnable || disallowIntercept)
{
return false;
}
|
|
switch (ev.Action)
|
{
case MotionEventActions.Down:
mLastX = ev.RawX;
mLastY = ev.RawY;
bAlreadyToTop = false;
|
System.Console.WriteLine($"MotionEventActions.Down");
|
Parent?.RequestDisallowInterceptTouchEvent(true);
break;
|
case MotionEventActions.Up:
Parent?.RequestDisallowInterceptTouchEvent(true);
|
System.Console.WriteLine($"MotionEventActions.Up");
if (bAlreadyToTop)
|
{
|
AlreadyToTopUpAction?.Invoke();
|
System.Console.WriteLine($"AlreadyToTopUpAction");
|
}
break;
case MotionEventActions.Move:
var x = ev.RawX;
var y = ev.RawY;
var deltaX = x - mLastX;
var deltaY = y - mLastY;
|
System.Console.WriteLine($"MotionEventActions.Move");
if (Math.Abs(deltaX) < Math.Abs(deltaY))
|
{
|
//向下滑动,如果当前已经滑动到顶,就允许父控件的拦截事件
|
if (deltaY > 0 && ScrollY == 0)
|
{
|
bAlreadyToTop = true;
|
AlreadyToTopAction?.Invoke();
|
Parent?.RequestDisallowInterceptTouchEvent(false);
|
|
|
|
return false;
|
}
|
//向上滑动时,如果translateY等于高度时,即表明滑动到底部,可又顶层View控制滑动
|
var mChildH = 0;
|
if (0 < ChildCount)
|
{
|
mChildH = GetChildAt(ChildCount - 1).Bottom;
|
}
|
var translateY = mChildH - ScrollY;
|
if (deltaY < 0 && translateY == Height)
|
{
|
AlreadyToBottomAction?.Invoke();
|
Parent?.RequestDisallowInterceptTouchEvent(false);
|
|
return false;
|
}
|
}
|
else
|
{
//左右滑动时,允许父控件的拦截
|
if (4 < Math.Abs(deltaX))
|
{
|
Parent?.RequestDisallowInterceptTouchEvent(false);
|
}
}
break;
}
return base.OnInterceptTouchEvent(ev);
}
/// <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)
{
//System.Console.WriteLine($"{GetType()} Height->{Height} Width->{Width} OnInterceptTouchEvent->{e.Action}");
_view?.TouchEvent(e);
base.OnTouchEvent(e);
//如果返回真父控件就不需要处理了
return true;
}
bool disallowIntercept;
public override void RequestDisallowInterceptTouchEvent(bool disallowIntercept)
{
this.disallowIntercept = disallowIntercept;
//System.Console.WriteLine($"{GetType()} Height->{Height} RequestDisallowInterceptTouchEvent->{disallowIntercept}");
base.RequestDisallowInterceptTouchEvent(disallowIntercept);
Parent?.RequestDisallowInterceptTouchEvent(disallowIntercept);
}
}
|
|
|
|
|
class MyLoadingHorizontal : Android.Widget.LinearLayout
|
{
|
ProgressBar Progress;
|
public Android.Widget.TextView textView;
|
LinearLayout tempLinearLayout;
|
|
|
public void ShowProgress()
|
{
|
Progress.Visibility = ViewStates.Visible;
|
|
}
|
|
public void HideProgress()
|
{
|
Progress.Visibility = ViewStates.Gone;
|
|
}
|
public MyLoadingHorizontal(Context context)
|
: base(context)
|
{
|
|
Progress = new ProgressBar(context);
|
|
|
//SetBackgroundColor (Android.Graphics.Color.Argb (50, 0x32, 0x32, 0x32));
|
SetGravity(GravityFlags.Center);
|
tempLinearLayout = new MiddleLinearLayout(context) { Orientation = Orientation.Horizontal };
|
tempLinearLayout.SetGravity(GravityFlags.CenterHorizontal);
|
|
|
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WrapContent, Application.GetRealHeight(30));
|
lp.Gravity = Android.Views.GravityFlags.Center;
|
tempLinearLayout.AddView(Progress, lp);
|
|
|
|
textView = new Android.Widget.TextView(context);
|
textView.Text = "Loading.....";
|
textView.Gravity = GravityFlags.Center;
|
tempLinearLayout.AddView(textView, new Android.Views.ViewGroup.LayoutParams(Android.Views.ViewGroup.LayoutParams.WrapContent, Application.GetRealHeight(40)));
|
AddView(tempLinearLayout, new Android.Views.ViewGroup.LayoutParams(Android.Views.ViewGroup.LayoutParams.WrapContent, Android.Views.ViewGroup.LayoutParams.WrapContent));
|
tempLinearLayout.SetPadding(20, 20, 20, 20);
|
}
|
|
uint LoadingHorizontalBackgroundColor;
|
/// <summary>
|
/// 背景颜色
|
/// </summary>
|
/// <value>The color of the background.</value>
|
public virtual uint LodingBackgroundColor
|
{
|
get
|
{
|
return LoadingHorizontalBackgroundColor;
|
}
|
set
|
{
|
LoadingHorizontalBackgroundColor = value;
|
|
if (this.GetType() != typeof(ImageView))
|
{
|
if (tempLinearLayout.Background == null || tempLinearLayout.Background.GetType() != typeof(GradientDrawable))
|
{
|
tempLinearLayout.Background = new Android.Graphics.Drawables.GradientDrawable();
|
}
|
|
var gradientDrawable = (GradientDrawable)tempLinearLayout.Background;
|
gradientDrawable.SetCornerRadius(DensityUtil.Dip2Px(6));
|
byte r, g, b, a;
|
|
r = (byte)(LoadingHorizontalBackgroundColor / 256 / 256 % 256);
|
g = (byte)(LoadingHorizontalBackgroundColor / 256 % 256);
|
b = (byte)(LoadingHorizontalBackgroundColor % 256);
|
a = (byte)(LoadingHorizontalBackgroundColor / 256 / 256 / 256 % 256);
|
gradientDrawable.SetColor(Android.Graphics.Color.Argb(a, r, g, b).ToArgb());
|
}
|
}
|
}
|
|
/// <summary>
|
/// 点击事件
|
/// </summary>
|
/// <returns>The touch event.</returns>
|
/// <param name="e">E.</param>
|
public override bool OnTouchEvent(Android.Views.MotionEvent e)
|
{
|
//事件自己处理
|
return true;
|
}
|
}
}
|