using System;
using Android.Views;
using Android.Content;
using Android.Widget;
using Android.Graphics.Drawables;
namespace Shared
{
///
/// 首页轮播图
///
public class HorizontalPages : ViewGroup
{
///
/// 视图高度
///
/// The height.
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;
}
}
///
/// 视图宽度
///
/// The width.
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;
}
}
//InnerHorizontalPages (realViewGroup as InnerHorizontalPages);
///
/// 页面变化事件
///
public Action PageChange;
///
/// 开始滑动事件
///
public Action StartScrollAction;
///
/// 结束滑动事件
///
public Action EndScrollAction;
/////
///// 没有更多提示Action,已经是最后一个
/////
//public Action NoMoreAction;
///
/// 构造函数
///
public HorizontalPages()
{
viewGroup = new AndroidFrameLayout(Application.Activity, null);
realViewGroup = new InnerHorizontalPages(Application.Activity, this) { };
//realViewGroup = InnerHorizontalPages;
viewGroup.AddView(realViewGroup);
}
ImageView LeftImageView;
ImageView RightImageView;
///
/// 是否设置了虚假背景View 设置了才显示
///
public bool IsSetLeftAndRightImageView = false;
///
/// 设置控制最左和最右2边,填充的假背景View,不设置不显示,需要在AddChidren 前调用该方法
///
///
///
public void SetLeftAndRightImageView(ImageView mLeftImageView, ImageView mRightImageView)
{
if (mLeftImageView == null) return;
if (mRightImageView == null) return;
//设置之前先清空一次
(realViewGroup as InnerHorizontalPages).RemoveAllViews();
LeftImageView = mLeftImageView;
(realViewGroup as InnerHorizontalPages).AddView(LeftImageView.AndroidView);
LeftImageView.Parent = this;
LeftImageView.Refresh();
RightImageView = mRightImageView;
(realViewGroup as InnerHorizontalPages).AddView(RightImageView.AndroidView);
RightImageView.Parent = this;
RightImageView.Refresh();
IsSetLeftAndRightImageView = true;
}
int pageIndex;
///
/// 设置或者获取当前的界面索引
///
/// The index of the page.
public int PageIndex
{
get
{
return (realViewGroup as InnerHorizontalPages).CurrentScreen;
}
set
{
if (value < 0 || ChildrenCount < value)
{
return;
}
pageIndex = value;
if (!IsCanRefresh)
{
return;
}
(realViewGroup as InnerHorizontalPages).SetSelection(value);
}
}
///
/// 是否允许滑动
///
/// true if scroll enabled; otherwise, false.
public bool ScrollEnabled
{
get
{
return (realViewGroup as InnerHorizontalPages).ScrollEnabled;
}
set
{
(realViewGroup as InnerHorizontalPages).ScrollEnabled = value;
}
}
///
/// 增加子控件
///
/// View.
public override void AddChidren(View view)
{
view.Parent = this;
viewList.Add(view);
(realViewGroup as InnerHorizontalPages).AddView(view.AndroidView);
if (!IsCanRefresh)
{
return;
}
view.Refresh();
if (view is ViewGroup)
{
var tempViewGroup = (ViewGroup)view;
for (int i = 0; i < tempViewGroup.ChildrenCount; i++)
{
tempViewGroup.GetChildren(i).Refresh();
}
}
}
///
/// 移除当前控件
///
/// View.
internal override void Remove(View view)
{
//if (view == null)
//{
// return;
//}
//var index = viewList.FindIndex(obj => obj == view);
//if (index < 0)
//{
// return;
//}
//viewList.Remove(view);
//(realViewGroup as InnerHorizontalPages).RemoveViewAt(index);
//view.Parent = null;
base.Remove(view);
(realViewGroup as InnerHorizontalPages).ReLocation();
if (PageIndex > ChildrenCount - 1)
{
PageIndex = ChildrenCount - 1;
}
}
///
/// 移除所有的控件
///
public override void RemoveAll()
{
//while (0 < viewList.Count)
//{
// GetChildren(0)?.RemoveFromParent();
//}
//(realViewGroup as InnerHorizontalPages).SetSelection(0);
base.RemoveAll();
(realViewGroup as InnerHorizontalPages).ReLocation();
PageIndex = 0;
}
///
/// 根据索引移除控件
///
/// Index.
public override void RemoveAt(int index)
{
if (viewList.Count - 1 < index || index < 0)
{
return;
}
Remove(viewList[index]);
}
///
/// 界面之间的边距
///
public int JMBJ
{
get
{
return (realViewGroup as InnerHorizontalPages).JMBJ;
}
set
{
(realViewGroup as InnerHorizontalPages).JMBJ = value;
(realViewGroup as InnerHorizontalPages).RefreshPageWidth();
}
}
///
/// 突出宽度
///
public int TCBJ
{
get
{
return (realViewGroup as InnerHorizontalPages).TCBJ;
}
set
{
(realViewGroup as InnerHorizontalPages).TCBJ = value;
(realViewGroup as InnerHorizontalPages).RefreshPageWidth();
}
}
//********************Transform3D 旋转效果方法**********************
////默认20度
//float transformAngle = 20;
////旋转角度
//public int TransformAngle
//{
// set
// {
// transformAngle = value;
// }
//}
//
//public void RefreshPageView()
//{
// //RefreshViewWithTransform3D();
// //RefreshViewWithChangeHeight();
// (realViewGroup as InnerHorizontalPages).RefreshViewWithChangeHeight();
//}
//public void RefreshViewWithTransform3D()
//{
// if (viewList.Count <= 0) return;
// if (PageIndex > viewList.Count - 1)
// {
// PageIndex = viewList.Count - 1;
// }
// viewList[PageIndex].AndroidView.RotationY = 0;
// //判断PageIndex 前后是否有view,并旋转
// if (PageIndex - 1 >= 0)
// {
// viewList[PageIndex - 1].AndroidView.RotationY = transformAngle;
// }
// if (PageIndex <= viewList.Count - 2)
// {
// viewList[PageIndex + 1].AndroidView.RotationY = -1 * transformAngle;
// }
//}
public bool isScrolling;
///
/// 是否正在滑动
///
public bool ISScrolling
{
get
{
return isScrolling;
}
}
///
/// 是否正在滑动
///
/// true if decelerating; otherwise, false.
public bool Decelerating
{
get
{
return isScrolling;
}
}
}
public class InnerHorizontalPages : Android.Widget.FrameLayout
{
public bool ScrollEnabled = true;
static int snapVelocity = 1000;
static int invalidScreen = -1;
static int touchStateRest = 0;
static int touchStateScrolling = 1;
///
/// 界面之间的边距
///
public int JMBJ = 0;
//突出宽度
public int TCBJ = 100;
Scroller scroller;
VelocityTracker mVelocityTracker = VelocityTracker.Obtain();
int touchState = touchStateRest;
float lastMotionX;
float lastMotionY;
int mTouchSlop;
int mMaximumVelocity;
internal int CurrentScreen;
int mPageWidth;
public void RefreshPageWidth()
{
mPageWidth = (int)LayoutParameters.Width - 2 * (TCBJ + JMBJ);
}
//public override void RemoveViewAt(int index)
//{
// int nowScreen = CurrentScreen;
// if (index == horizontalPages.ChildrenCount - 1)
// {
// nowScreen--;
// if (nowScreen < 0)
// {
// nowScreen = 0;
// }
// }
// base.RemoveViewAt(index);
// ReLocation();
// snapToScreen(nowScreen, true);
// //刷新
// //snapToDestination();
//}
Shared.HorizontalPages horizontalPages;
public InnerHorizontalPages(Context context, Shared.HorizontalPages view) : base(context)
{
horizontalPages = view;
init();
}
///
/// 重写这个是为了方便部局,在每个界面之间都多加了一个控件包住
///
///
public override void AddView(Android.Views.View child)
{
base.AddView(child);
ReLocation();
}
///
/// 重新排位置及设备内容大小
///
public virtual void ReLocation()
{
try
{
if (horizontalPages.ChildrenCount == 0)
{
return;
}
horizontalPages.GetChildren(0).AndroidView.SetX(TCBJ + JMBJ);
for (int i = 1; i < horizontalPages.ChildrenCount; i++)
{
horizontalPages.GetChildren(i).AndroidView.SetX((int)horizontalPages.GetChildren(i - 1).AndroidView.GetX() + horizontalPages.GetChildren(i - 1).AndroidView.LayoutParameters.Width + JMBJ);
}
if (horizontalPages.IsSetLeftAndRightImageView)
{
var mHeight = LayoutParameters.Height - JMBJ * 2;
//System.Console.WriteLine("ChildCountl:"+ChildCount.ToString() + " ChildrenCount:" + horizontalPages.ChildrenCount);
var layoutParameters = GetChildAt(0).LayoutParameters;
layoutParameters.Width = mPageWidth;
layoutParameters.Height = mHeight;
GetChildAt(0).LayoutParameters = layoutParameters;
GetChildAt(0).SetX(TCBJ - mPageWidth);
GetChildAt(0).SetY(JMBJ);
var layoutParameters2 = GetChildAt(1).LayoutParameters;
layoutParameters2.Width = mPageWidth;
layoutParameters2.Height = mHeight;
GetChildAt(1).LayoutParameters = layoutParameters2;
GetChildAt(1).SetY(JMBJ);
GetChildAt(1).SetX((int)horizontalPages.GetChildren(horizontalPages.ChildrenCount - 1).AndroidView.GetX() + mPageWidth + JMBJ);
}
RefreshPageView();
}
catch { }
}
///
///
///
///
bool CheckIfStartOrEnd()
{
return (deltaX > 0 && CurrentScreen == horizontalPages.ChildrenCount - 1) || (deltaX < 0 && CurrentScreen == 0);
}
///
/// 判断是否需要发送结束滑动事件
///
void SendEndScrollAction()
{
if (isStart)
{
isStart = false;
horizontalPages.EndScrollAction?.Invoke();
}
}
//bool isNoMore;
bool isStart;
int moveX;
void init()
{
scroller = new Scroller(Context);
var configuration = ViewConfiguration.Get(Context);
//最小的滑动距离
mTouchSlop = configuration.ScaledTouchSlop;
mMaximumVelocity = configuration.ScaledMaximumFlingVelocity;
ScrollChange += (s, e) =>
{
moveX = ScrollX - beforeXScrollX;
RefreshPageView();
//Shared.HDLUtils.WriteLine($"HorizontalPages Scrolled ScrollX:{ScrollX} WIDTH:{Width}");
if (mTouchSlop < Math.Abs(moveX))
{
if (!isStart)
{
//当前索引为,不是第一个或者最后一个,滑动距离大于触发距离并且没执行过则 执行一次StartScrollAction
if ((moveX > 0 && CurrentScreen < horizontalPages.ChildrenCount - 1) || (moveX < 0 && CurrentScreen > 0))
{
isStart = true;
horizontalPages.StartScrollAction?.Invoke();
}
}
}
};
}
///
/// 自动计算刷新所有View的高度,实现缩放效果
///
public void RefreshPageView()
{
//RefreshViewWithTransform3D();
RefreshViewWithChangeHeight();
}
///
/// 刷新最大距离值
///
double MaxDistance;
//public void RefreshMaxDistance()
//{
// MaxDistance = Width - 2 * TCBJ - JMBJ;
//}
///
/// 计算滑动缩放高度的方法
///
public void RefreshViewWithChangeHeight()
{
if (horizontalPages.ChildrenCount <= 0) return;
MaxDistance = LayoutParameters.Width - 2 * TCBJ - JMBJ;
//方法1
for (int i = 0; i < horizontalPages.viewList.Count; i++)
{
double distance = Math.Abs(horizontalPages.viewList[i].X - ScrollX - TCBJ - JMBJ);
var HH = 0;
if (distance <= 0)
{
HH = 0;
}
else if (distance >= MaxDistance)
{
HH = JMBJ;
}
else
{
HH = (int)((distance / MaxDistance) * JMBJ);
}
horizontalPages.viewList[i].Height = LayoutParameters.Height - HH * 2;
horizontalPages.viewList[i].Y = HH;
RefreshSubviewHeight(horizontalPages.viewList[i], horizontalPages.viewList[i].Height);
}
}
///
/// 同时刷新子view 和ImageView的高度,暂时解决底部圆角失效问题
///
///
///
void RefreshSubviewHeight(View mView, float height)
{
try
{
if (mView is ViewGroup)
{
var tempViewGroup = (ViewGroup)mView;
for (int i = 0; i < tempViewGroup.ChildrenCount; i++)
{
if (tempViewGroup.GetChildren(i) is ViewGroup)
{
var tempViewGroup2 = (ViewGroup)tempViewGroup.GetChildren(i);
for (int j = 0; j < tempViewGroup2.ChildrenCount; j++)
{
if (tempViewGroup2.GetChildren(j) is ImageView && tempViewGroup2.GetChildren(j).Tag.ToString() == "R")
{
tempViewGroup2.GetChildren(j).Height = (int)height;
break;
}
}
if (tempViewGroup2.Tag.ToString() == "R")
{
tempViewGroup2.Height = (int)height;
break;
}
}
}
}
}
catch { }
}
public override void RequestDisallowInterceptTouchEvent(bool disallowIntercept)
{
base.RequestDisallowInterceptTouchEvent(disallowIntercept);
disallowInterceptTouchEvent = disallowIntercept;
}
bool disallowInterceptTouchEvent;
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
if (disallowInterceptTouchEvent)
{
return false;
}
//Shared.HDLUtils.WriteLine($"HorizontalPages->OnInterceptTouchEvent:{Height} {ev.Action}");
//如果没有子控件或者不允许滑动就返回,不处理当前事件
if (horizontalPages.ChildrenCount == 0 || !ScrollEnabled)
return false;
mVelocityTracker.AddMovement(ev);
var x = ev.GetX();
var y = ev.GetY();
switch (ev.Action)
{
//每次点击都执行这里
case MotionEventActions.Down:
beforeXScrollX = ScrollX;
if (!scroller.IsFinished)
{
//如果还在滑动,但是用户重新点击了,就让控件马上停止
scroller.AbortAnimation();
}
//记录点击的最新X坐标
lastMotionX = x;
lastMotionY = y;
touchState = scroller.IsFinished ? touchStateRest : touchStateScrolling;
//IfAction = true;
//isNoMore = false;
//isStart = false;
////开始滑动事件
//horizontalPages.StartScrollAction?.Invoke() ;
break;
//有子控件时执行这里
case MotionEventActions.Move:
var deltaX = (int)(lastMotionX - x);
var deltaY = (int)(lastMotionY - y);
//当前滑动是否已经超出了设定值
var xMoved = Math.Abs(deltaX) > mTouchSlop;
if (xMoved && Math.Abs(deltaY) < Math.Abs(deltaX))
{
touchState = touchStateScrolling;
//isNoMore = false;
}
if (touchState == touchStateScrolling)
{
//记录最新的坐标,因为接下来控件已经滑动了
lastMotionX = x;
//当前事件自己处理了,子控制不需要处理当前这事件
return true;
}
break;
case MotionEventActions.Cancel:
touchState = touchStateRest;
mVelocityTracker.Clear();
break;
}
return false;
}
int deltaX;
int beforeXScrollX;
public override bool OnTouchEvent(MotionEvent e)
{
if (disallowInterceptTouchEvent)
{
return false;
}
if (horizontalPages.ChildrenCount == 0 || !ScrollEnabled)
return false;
mVelocityTracker.AddMovement(e);
var x = e.GetX();
var y = e.GetY();
switch (e.Action)
{
case MotionEventActions.Move:
SetIsScrolling(true);
deltaX = (int)(lastMotionX - x);
var deltaY = (int)(lastMotionY - y);
//当前滑动是否已经超出了设定值
var xMoved = Math.Abs(deltaX) > mTouchSlop;
if (xMoved && Math.Abs(deltaY) < Math.Abs(deltaX))
{
touchState = touchStateScrolling;
}
if (touchState == touchStateScrolling)
{
lastMotionX = x;
int scrollX = ScrollX;
//向右滑动
if (deltaX < 0)
{
//之前已经滑动的X轴
if (scrollX > 0)
{
//向右滑动时显示出左边的界面,最低的长度为之前已经滑动的距离
ScrollBy(Math.Max(-scrollX, deltaX), 0);
}
}
//向左滑动
else if (deltaX > 0)
{
//最小的右边需要滑动的距离
int availableToScroll = (int)horizontalPages.GetChildren(
horizontalPages.ChildrenCount - 1).AndroidView.GetX() + horizontalPages.GetChildren(
horizontalPages.ChildrenCount - 1).AndroidView.LayoutParameters.Width + TCBJ + JMBJ
- PaddingRight - HorizontalFadingEdgeLength
- scrollX - Width;
if (availableToScroll > 0)
{
ScrollBy(Math.Min(availableToScroll, deltaX), 0);
}
}
return true;
}
break;
case MotionEventActions.Up:
case MotionEventActions.Cancel:
//IfAction = true;
if (touchState == touchStateScrolling)
{
mVelocityTracker.ComputeCurrentVelocity(1000, mMaximumVelocity);
var velocityX = mVelocityTracker.XVelocity;
var moveX = ScrollX - beforeXScrollX;
if (mTouchSlop < Math.Abs(moveX) || velocityX > snapVelocity)
{
if (moveX < 0)
{
// 显示左边界面
snapToScreen(CurrentScreen - 1);
}
else if (moveX > 0)
{
// 显示右边界面
snapToScreen(CurrentScreen + 1);
}
}
else
{
snapToScreen(CurrentScreen);
}
}
else
{
snapToScreen(CurrentScreen);
}
//if (Math.Abs(deltaX) > mTouchSlop)
//{
// if (!isNoMore && !bSendPageChange)
// {
// //当前索引为第一个或者最后一个,滑动距离大于触发距离、没执行过、PageIndex没变化、则执行一次NoMoreAction
// if ((deltaX > 0 && CurrentScreen == horizontalPages.ChildrenCount - 1 && ScrollX >= Width) || (deltaX < 0 && CurrentScreen == 0 && ScrollX <= 0))
// {
// isNoMore = true;
// horizontalPages.NoMoreAction?.Invoke();
// }
// }
//}
touchState = touchStateRest;
mVelocityTracker.Clear();
break;
}
return true;
}
///
/// 滑动到指定的界面
///
public void snapToDestination(bool isDelay = true)
{
var whichScreen = (ScrollX + (MeasuredWidth / 2)) / MeasuredWidth;
snapToScreen(whichScreen, isDelay);
}
///
/// 滑动到指定界面
///
/// Which screen.
void snapToScreen(int whichScreen, bool isDelay = true)
{
if (!scroller.IsFinished)
{
scroller.AbortAnimation();
}
var beforePosition = CurrentScreen;
whichScreen = Math.Max(0, Math.Min(whichScreen, horizontalPages.ChildrenCount - 1));
CurrentScreen = whichScreen;
//还原这个控件之前的位置
int newX = 0;
if (CurrentScreen != 0)
{
newX = (int)horizontalPages.GetChildren(CurrentScreen).AndroidView.GetX() - TCBJ - JMBJ;
}
SetIsScrolling(true);
var delta = newX - ScrollX;
scroller.StartScroll(ScrollX, 0, delta, 0, isDelay ? 400 : 0);
Invalidate();
SendIfPageChange(isDelay ? 400 : 0);
//Shared.HDLUtils.WriteLine("HorizontalPages StartScroll");
if (beforePosition != CurrentScreen)
{
RefreshPageView();
bSendPageChange = true;
//DelayPageChange();
//horizontalPages.PageChange?.Invoke(horizontalPages, CurrentScreen);
}
}
private void SetIsScrolling(bool bSctolling)
{
if (horizontalPages.isScrolling == bSctolling) return;
//Shared.HDLUtils.WriteLine($"HorizontalPages StartScroll: {bSctolling}");
horizontalPages.isScrolling = bSctolling;
}
System.Threading.Thread sendThread;
//string SendmarkStr;
bool bSendPageChange = false;
///
/// 判断是否要发送改变事件
///
private void SendIfPageChange(int DELAY = 400)
{
try
{
if (sendThread != null)
sendThread.Abort();
sendThread = new System.Threading.Thread(async () =>
{
System.Threading.Thread.Sleep(DELAY + 100);
Application.RunOnMainThread(() =>
{
SetIsScrolling(false);
if (bSendPageChange)
{
bSendPageChange = false;
horizontalPages.PageChange?.Invoke(horizontalPages, CurrentScreen);
}
SendEndScrollAction();
HDLUtils.WriteLine($"HorizontalPages SendIfPageChange______________-----------");
});
})
{ IsBackground = true };
sendThread.Start();
}
catch
{
}
}
//public void DelayPageChange()
//{
// new System.Threading.Thread(async () =>
// {
// System.Threading.Thread.Sleep(500);
// Application.RunOnMainThread(() =>
// {
// horizontalPages.PageChange?.Invoke(horizontalPages, CurrentScreen);
// });
// })
// { IsBackground = true }.Start();
//}
public override void ComputeScroll()
{
if (scroller.ComputeScrollOffset())
{
ScrollTo(scroller.CurrX, scroller.CurrY);
PostInvalidate();
}
else if (CurrentScreen != invalidScreen)
{
//mCurrentScreen = Math.Max(0, Math.Min(mNextScreen, horizontalPages.ChildrenCount - 1));
//mNextScreen = invalidScreen;
//postViewSwitched(mLastScrollDirection);
}
}
public void SetSelection(int position)
{
if (position < 0)
{
return;
}
scroller.ForceFinished(true);
position = Math.Min(position, horizontalPages.ChildrenCount - 1);
if(position != CurrentScreen)
{
isStart = true;
horizontalPages.StartScrollAction?.Invoke();
}
snapToScreen(position, false);
}
public override bool DispatchTouchEvent(MotionEvent e)
{
//Shared.HDLUtils.WriteLine($"PageLayout->DispatchTouchEvent:{Height} {e.Action}");
if (e.Action == MotionEventActions.Down)
{
//还原中断
RequestDisallowInterceptTouchEvent(false);
Parent.RequestDisallowInterceptTouchEvent(true);
}
else if (e.Action == MotionEventActions.Up || e.Action == MotionEventActions.Cancel)
{
Parent.RequestDisallowInterceptTouchEvent(false);
}
return base.DispatchTouchEvent(e);
}
}
}