using System; using Android.Graphics.Drawables; using Android.Graphics; using Android.Views.Animations; using Android.Views; using Java.Lang.Ref; using static Shared.HDLUtils; using Android.OS; namespace Shared { /// /// 根视图 /// internal class RootView : ViewGroup { } /// /// 所有类的基类 /// public abstract class View { ~View() { //#if DEBUG Shared.HDLUtils.WriteLine("=====" + GetType() + " " + Name); //#endif if (this is ViewGroup) { var viewGroup = this as ViewGroup; if (viewGroup.realViewGroup != AndroidView) { //foreach (var view in viewGroup.viewList) //{ // view.AndroidView.Dispose(); //} viewGroup.realViewGroup?.Dispose(); } } AndroidView?.Dispose(); } /// /// 是否需要更新控件 /// /// The is need refresh. protected bool IsCanRefresh { get { View tempView = Parent; while (tempView != null) { //根控件,找到根控件后说明已经成功加入了父控件 if (tempView.GetType() == typeof(RootView)) { return true; } tempView = tempView.Parent; } return false; } } internal virtual void ClearAllViewEvent() { //try //{ // lock (dimageCached) // { // foreach (var key in dimageCached.KeySet()) // { // var keyString = key.ToString(); // if (keyString.StartsWith($"{GetHashCode()}_", StringComparison.Ordinal)) // { // dimageCached.Remove(keyString); // Shared.HDLUtils.WriteLine("=====释放图片" + GetType() + " " + Name); // (dimageCached.Get(keyString) as Drawable)?.Dispose(); // break; // } // } // } //} //catch { } } internal virtual void InitAllViewEvent() { } /// /// 当前对应的AndroidView控件 /// public Android.Views.View AndroidView { get; set; } /// /// 是否使能 /// /// The enable. public virtual bool Enable { get { return AndroidView.Enabled; } set { AndroidView.Enabled = value; } } int height = LayoutParams.MatchParent; /// /// 控件的高度 /// /// The height. public virtual int Height { get { return AndroidView.LayoutParameters == null ? height : AndroidView.LayoutParameters.Height; } set { height = value; if (!IsCanRefresh) return; var layoutParameters = AndroidView.LayoutParameters; if (value == LayoutParams.MatchParent) { if (layoutParameters.Height != Parent.Height) { layoutParameters.Height = Parent.Height; AndroidView.LayoutParameters = layoutParameters; SizeChangeEventHandler?.Invoke(this, new Size(layoutParameters.Width, layoutParameters.Height)); } } else { if (layoutParameters.Height != value) { layoutParameters.Height = value; AndroidView.LayoutParameters = layoutParameters; SizeChangeEventHandler?.Invoke(this, new Size(layoutParameters.Width, layoutParameters.Height)); } } } } int width = LayoutParams.MatchParent; /// /// 控件宽度 /// /// The width. public virtual int Width { get { return AndroidView.LayoutParameters == null ? width : AndroidView.LayoutParameters.Width; } set { width = value; if (!IsCanRefresh) return; var layoutParameters = AndroidView.LayoutParameters; if (value == LayoutParams.MatchParent) { if (layoutParameters.Width != Parent.Width) { layoutParameters.Width = Parent.Width; AndroidView.LayoutParameters = layoutParameters; SizeChangeEventHandler?.Invoke(this, new Size(layoutParameters.Width, layoutParameters.Height)); } } else { if (layoutParameters.Width != value) { layoutParameters.Width = value; AndroidView.LayoutParameters = layoutParameters; SizeChangeEventHandler?.Invoke(this, new Size(layoutParameters.Width, layoutParameters.Height)); } } } } /// /// 刷新界面 /// public virtual void Refresh() { Width = width; Height = height; Gravity = gravity; Animate = animate; Radius = tempRadius; } /// /// 名称 /// /// The name. public string Name { get; set; } int x; /// /// X轴坐标 /// /// The x. public int X { get { return (int)AndroidView.GetX(); } set { x = value; if (!IsCanRefresh) { return; } if (Parent is HorizontalPages|| Parent is HorizontalScrolViewLayout) { return; } else { AndroidView.SetX(value); } } } int y; /// /// Y轴坐标 /// /// The y. public int Y { get { return (int)AndroidView.GetY(); } set { y = value; if (!IsCanRefresh) { return; } if (Parent.GetType() == typeof(VerticalScrolViewLayout)) { return; } else { AndroidView.SetY(value); } } } Gravity gravity = Gravity.Frame; /// /// 控件相对于父控件的对齐方式 /// /// The gravity. public Gravity Gravity { get { return gravity; } set { gravity = value; if (!IsCanRefresh) { return; } switch (value) { case Gravity.TopLeft: X = 0; Y = 0; break; case Gravity.TopCenter: X = (Parent.Width - Width) / 2; Y = 0; break; case Gravity.TopRight: X = Parent.Width - Width; Y = 0; break; case Gravity.CenterLeft: X = 0; Y = (Parent.Height - Height) / 2; break; case Gravity.Center: X = (Parent.Width - Width) / 2; Y = (Parent.Height - Height) / 2; break; case Gravity.CenterRight: X = Parent.Width - Width; Y = (Parent.Height - Height) / 2; break; case Gravity.BottomLeft: X = 0; Y = Parent.Height - Height; break; case Gravity.BottomCenter: X = (Parent.Width - Width) / 2; Y = Parent.Height - Height; break; case Gravity.BottomRight: X = Parent.Width - Width; Y = Parent.Height - Height; break; case Gravity.CenterVertical: X = x; Y = (Parent.Height - Height) / 2; break; case Gravity.CenterHorizontal: X = (Parent.Width - Width) / 2; Y = y; break; case Gravity.Frame: X = x; Y = y; break; } } } /// /// 左边线位置 /// /// The bottom. public int Bottom { get { return Height + Y; } } /// /// 右边线位置 /// /// The right. public int Right { get { return Width + X; } } /// /// 当前窗口大小及位置 /// /// The frame. public virtual Size Size { get { return new Size(Width, Height); } set { Width = value.Width; Height = value.Height; } } /// /// 父容器 /// /// The parent. public ViewGroup Parent { get; internal set; } /// /// 处理点击代理 /// /// Sender. /// E. internal virtual bool TouchEvent(MotionEvent e) { if (!this.Enable) { return false; } switch (e.Action) { case MotionEventActions.Down: isUp = false; longClicked = false; MouseDownEventHandler?.Invoke(this, new MouseEventArgs { X = (int)e.GetX(), Y = (int)e.GetY() }); if (MouseLongEventHandler != null) { try { if (thread != null && thread.IsAlive) { thread.Abort(); } thread = new System.Threading.Thread(() => { System.Threading.Thread.Sleep(800); //Shared.HDLUtils.WriteLine("=====" + isUp); if (!isUp) { longClicked = true; Application.RunOnMainThread(() => { MouseLongEventHandler(this, new MouseEventArgs { X = (int)e.GetX(), Y = (int)e.GetY() }); }); } }) { IsBackground = true }; thread.Start(); } catch { } } break; case MotionEventActions.Move: MouseMoveEventHandler?.Invoke(this, new MouseEventArgs { X = (int)e.GetX(), Y = (int)e.GetY() }); break; case MotionEventActions.Up: isUp = true; if (!longClicked && isTouchPointInView(AndroidView, e.RawX, e.RawY)) { MouseUpEventHandler?.Invoke(this, new MouseEventArgs { X = (int)e.GetX(), Y = (int)e.GetY() }); } break; case MotionEventActions.Cancel: isUp = true; break; } return true; } private bool isTouchPointInView(Android.Views.View targetView, float xAxis, float yAxis) { if (targetView == null) { return false; } var location = new int[2]; targetView.GetLocationOnScreen(location); int left = location[0]; int top = location[1]; int right = left + targetView.Width; int bottom = top + targetView.Height; if (yAxis >= top && yAxis <= bottom && xAxis >= left && xAxis <= right) { return true; } return false; } bool isUp ; bool longClicked; /// /// 点击按下事件 /// public EventHandler MouseDownEventHandler; /// /// 控件上移动事件 /// public EventHandler MouseMoveEventHandler; /// /// 点击弹起事件 /// public EventHandler MouseUpEventHandler; System.Threading.Thread thread; /// /// 长按点击事件 /// public EventHandler MouseLongEventHandler; /// /// 大小变化事件 /// public EventHandler SizeChangeEventHandler; /// /// 将控制移到最前 /// public virtual void BringToFront() { AndroidView.BringToFront(); } Animate animate = Animate.None; /// /// 动画方式 /// /// The animate. public Animate Animate { get { return animate; } set { animate = value; if (!IsCanRefresh) { return; } AndroidView.ClearAnimation(); switch (animate) { case Animate.DownToUp: { AndroidView.Animation = new TranslateAnimation( Dimension.RelativeToSelf, 0, Dimension.RelativeToSelf, 0, Dimension.RelativeToSelf, 1.0f, Dimension.RelativeToSelf, 0) { Duration = 500 }; // 13828497568 AndroidView.Animation.StartNow(); } break; case Animate.UpToDown: { AndroidView.Animation = new TranslateAnimation( Dimension.RelativeToSelf, 0, Dimension.RelativeToSelf, 0, Dimension.RelativeToSelf, -1.0f, Dimension.RelativeToSelf, 0) { Duration = 500 }; AndroidView.Animation.StartNow(); } break; case Animate.LeftToRight: { AndroidView.Animation = new TranslateAnimation( Dimension.RelativeToSelf, -1.0f, Dimension.RelativeToSelf, 0, Dimension.RelativeToSelf, 0f, Dimension.RelativeToSelf, 0) { Duration = 500 }; AndroidView.Animation.StartNow(); } break; case Animate.RightToLeft: { AndroidView.Animation = new TranslateAnimation( Dimension.RelativeToSelf, 1.0f, Dimension.RelativeToSelf, 0, Dimension.RelativeToSelf, 0f, Dimension.RelativeToSelf, 0) { Duration = 500 }; AndroidView.Animation.StartNow(); } break; case Animate.Rotation: { AndroidView.Animation = new RotateAnimation( 0, 359, X + Width / 2.0f, Y + Height / 2.0f ) { Duration = 16000, RepeatCount = -1 }; AndroidView.Animation.StartNow(); } break; } } } static Java.Util.HashMap dimageCached = new Java.Util.HashMap(); /// /// 设备控件背景图 /// /// protected bool Background(string filePath) { try { var drawable = getDrawable(filePath); if (this.GetType() == typeof(ImageView)) { (AndroidView as AndroidImageView).SetImageDrawable(drawable); } else { AndroidView.Background = drawable; } if (null != drawable) { return true; } } catch { } return false; } protected bool Background(string filePath, Android.Views.View view) { AndroidView.Background = getDrawable(filePath); if (null == view.Background) { return false; } else { return true; } } protected Drawable Bytes2Drawable(byte[] b) { var bitmap = Bytes2Bitmap(b); return bitmap2Drawable(bitmap); } protected Drawable bitmap2Drawable(Bitmap bitmap) { return new BitmapDrawable(bitmap); } // byte[]转换成Bitmap protected Bitmap Bytes2Bitmap(byte[] b) { if (b.Length != 0) { return BitmapFactory.DecodeByteArray(b, 0, b.Length); } return null; } protected Drawable getDrawable(string filePath) { try { if (filePath == null) { return null; } var newFilePath = IO.FileUtils.GetImageFilePath(filePath); if (string.IsNullOrEmpty(newFilePath)) { AndroidView.Background = null; return null; } var mappingPath = "";// $"{this.GetHashCode()}_"; if (AndroidView.LayoutParameters != null) { mappingPath += AndroidView.LayoutParameters.Width + "-" + AndroidView.LayoutParameters.Height + "-"; } mappingPath += newFilePath; //lock (dimageCached) { if (dimageCached.ContainsKey(mappingPath) && dimageCached.Get(mappingPath) != null) { return (Drawable)dimageCached.Get(mappingPath); } } //Shared.HDLUtils.WriteLine(dimageCached.Size() + " "); var tempBitmapUtiles = AndroidDrawableUtiles.GetAndroidDrawableUtiles(newFilePath, Width, Height); //加载二次 if (null == tempBitmapUtiles) { tempBitmapUtiles = AndroidDrawableUtiles.GetAndroidDrawableUtiles(newFilePath, Width, Height); } //两次加载图片都失败,直接返回 if (null == tempBitmapUtiles) { AndroidView.Background = null; return null; } //if (mappingPath.Contains("/Room/") || mappingPath.Contains("/Scene/")) //{ // return tempBitmapUtiles.Drawable; //} //lock (dimageCached) { try { if (dimageCached.ContainsKey(mappingPath)) { dimageCached.Remove(mappingPath); dimageCached.Put(mappingPath, tempBitmapUtiles.Drawable); } else { dimageCached.Put(mappingPath, tempBitmapUtiles.Drawable); } return tempBitmapUtiles.Drawable; } catch { return null; } } } catch { return null; } } /// /// 内边距 /// /// The padding. public virtual Padding Padding { get; set; } /// /// 方便开发者开发 /// public object Tag; System.Collections.Generic.Dictionary tag; /// /// 增加键值对 /// /// Key. /// Value. public void AddTag(string key, object value) { if (tag == null) { tag = new System.Collections.Generic.Dictionary(); } tag.Remove(key); tag.Add(key, value); } /// /// 删除指定键值对 /// /// Key. public void RemoveTag(string key) { if (tag == null) { return; } tag.Remove(key); } /// /// 根据键获取值 /// /// The tag by key. /// Key. public object GetTagByKey(string key) { if (tag == null) { return null; } object value; tag.TryGetValue(key, out value); return value; } /// /// 全部删除Tag /// /// The tag. public void ClearTag() { if (tag != null) { tag.Clear(); } } /// /// 是否显示 /// /// true if visible; otherwise, false. public bool Visible { get { if (AndroidView.Visibility == Android.Views.ViewStates.Visible) { return true; } else { return false; } } set { if (value) { AndroidView.Visibility = Android.Views.ViewStates.Visible; } else { AndroidView.Visibility = Android.Views.ViewStates.Invisible; } } } /// /// 从父视图中移除 /// public virtual void RemoveFromParent() { if (Parent == null) { return; } Parent.Remove(this); } /// /// 透明度设置 /// /// The alpha. public float Alpha { get { return AndroidView.Alpha; } set { AndroidView.Alpha = value; } } uint backgroundColor; /// /// 背景颜色 /// /// The color of the background. public virtual uint BackgroundColor { get { return backgroundColor; } set { backgroundColor = value; if (this.GetType() != typeof(ImageView)) { if (AndroidView.Background == null || AndroidView.Background.GetType() != typeof(GradientDrawable)) { AndroidView.Background = new Android.Graphics.Drawables.GradientDrawable(); } var gradientDrawable = (GradientDrawable)AndroidView.Background; //gradientDrawable.SetCornerRadius(DensityUtil.Dip2Px(Radius)); if (IsSetAloneRadius) { gradientDrawable.SetCornerRadii(GetCornerRadii()); } else { gradientDrawable.SetCornerRadius(Radius); } byte r, g, b, a; r = (byte)(BorderColor / 256 / 256 % 256); g = (byte)(BorderColor / 256 % 256); b = (byte)(BorderColor % 256); a = (byte)(BorderColor / 256 / 256 / 256 % 256); gradientDrawable.SetStroke((int)BorderWidth, Android.Graphics.Color.Argb(a, r, g, b)); r = (byte)(backgroundColor / 256 / 256 % 256); g = (byte)(backgroundColor / 256 % 256); b = (byte)(backgroundColor % 256); a = (byte)(backgroundColor / 256 / 256 / 256 % 256); gradientDrawable.SetColor(Android.Graphics.Color.Argb(a, r, g, b).ToArgb()); } } } /// /// 获取指定圆角属性 /// /// The corner. private float[] GetCornerRadii() { float[] mCornerRadius = new float[8]; mCornerRadius[0] = topLeftRadius; mCornerRadius[1] = topLeftRadius; mCornerRadius[2] = topRightRadius; mCornerRadius[3] = topRightRadius; mCornerRadius[4] = bottomRightRadius; mCornerRadius[5] = bottomRightRadius; mCornerRadius[6] = bottomLeftRadius; mCornerRadius[7] = bottomLeftRadius; return mCornerRadius; } //是否单独设置圆角 public bool IsSetAloneRadius; //4个圆角分别对应的值 float topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius; public float mAloneRadius; public int mRadiusId; /// /// 指定位置 设置相同的圆角 /// public void SetCornerWithSameRadius(float mRadius, int mSetID) { try { mAloneRadius = mRadius; IsSetAloneRadius = true; mRadiusId = mSetID; topLeftRadius = (mSetID & 1) == 1 ? mAloneRadius : 0; topRightRadius = (mSetID >> 1 & 1) == 1 ? mAloneRadius : 0; bottomLeftRadius = (mSetID >> 2 & 1) == 1 ? mAloneRadius : 0; bottomRightRadius = (mSetID >> 3 & 1) == 1 ? mAloneRadius : 0; BackgroundColor = backgroundColor; } catch { } } internal uint radius, tempRadius; /// /// 圆角大小 /// /// The corner. public virtual uint Radius { get { return radius; } set { IsSetAloneRadius = false; tempRadius = value; if (!IsCanRefresh || Radius == value) { return; } radius = value; BackgroundColor = backgroundColor; } } uint borderWidth; /// /// 边框线大小 /// /// The width of the border. public uint BorderWidth { get { return borderWidth; } set { borderWidth = value; BackgroundColor = backgroundColor; } } uint borderColor = 0xFFCCCCCC; /// /// 边框颜色 /// /// The color of the border. public uint BorderColor { get { return borderColor; } set { borderColor = value; BackgroundColor = backgroundColor; } } protected int Dip2Px(float dpValue) { float scale = Application.Activity.Resources.DisplayMetrics.Density; return (int)(dpValue * scale + 0.5f); } /// /// 旋转View /// /// 旋转角度 public void SetRotation(float mRotation) { AndroidView.Rotation = mRotation; } /// /// 设置阴影效果 /// /// 是否显示阴影 public void SetViewShadow(bool bShow, float mOffsetY = 5.0f) { if((int)Build.VERSION.SdkInt >= 21) { //AndroidView.TranslationZ = bShow ? Dip2Px(mOffsetY) : 0; AndroidView.Elevation = bShow ? Dip2Px(mOffsetY) : 0; } } } public class Size { /// /// Initializes a new instance of the class. /// /// X轴 /// Y轴 /// 宽度 /// 高度 public Size(int width, int height) { Width = width; Height = height; } /// /// 宽度 /// public int Width { get; set; } /// /// 高度 /// public int Height { get; set; } } /// /// 内边距 /// public class Padding { public Padding(int top, int left, int bottom, int right) { Top = top; Left = left; Bottom = bottom; Right = right; } /// /// 顶部 /// public int Top { get; set; } /// /// 左边 /// public int Left { get; set; } /// /// 底部 /// public int Bottom { get; set; } /// /// 右边 /// public int Right { get; set; } } internal class AndroidDrawableUtiles { /// /// 图片对象 /// public Drawable Drawable; /// /// 图片的高度 /// public int Height; /// /// 图片的宽度 /// public int Width; /// /// Initializes a new instance of the class. /// /// Bitmap drawable. /// Height. /// Width. public AndroidDrawableUtiles(Drawable bitmapDrawable, int height, int width) { Drawable = bitmapDrawable; Height = height; Width = width; } static Bitmap readBitmapFromFileDescriptor(string filePath, int width, int height) { try { var fis = new Java.IO.FileInputStream(filePath); var options = new BitmapFactory.Options(); options.InJustDecodeBounds = true; BitmapFactory.DecodeFileDescriptor(fis.FD, null, options); float srcWidth = options.OutWidth; float srcHeight = options.OutHeight; int inSampleSize = 1; if (srcHeight > height || srcWidth > width) { if (srcWidth > srcHeight) { inSampleSize = (int)Math.Round(srcHeight / height); } else { inSampleSize = (int)Math.Round(srcWidth / width); } } options.InJustDecodeBounds = false; options.InSampleSize = inSampleSize; return (Bitmap)new SoftReference(BitmapFactory.DecodeFileDescriptor(fis.FD, null, options)).Get(); } catch (Exception ex) { } return null; } public static AndroidDrawableUtiles GetAndroidDrawableUtiles(string filePath, int width, int height) { var bitmap = readBitmapFromFileDescriptor(filePath, width, height); //BitmapFactory.Options options = new BitmapFactory.Options(); //options.InJustDecodeBounds = true; //BitmapFactory.DecodeFile(filePath, options); ////图片不存在,直接返回 //if (0 == options.OutWidth || 0 == options.OutHeight) //{ // Shared.HDLUtils.WriteLine(filePath+"找不到"); // return null; //} //options.InSampleSize = getFitInSampleSize(width, height, options); //options.InJustDecodeBounds = false; //var bitmap = BitmapFactory.DecodeFile(filePath, options); //var drawable = new BitmapDrawable(bitmap); //if (drawable.Bitmap != bitmap && !bitmap.IsRecycled) //{ // Shared.HDLUtils.WriteLine("释放图片资源:" + filePath); // bitmap.Recycle(); //} //var drawable = new BitmapDrawable(bitmap); if (bitmap == null) { return new AndroidDrawableUtiles(null, bitmap.Width, bitmap.Height); } else { return new AndroidDrawableUtiles((BitmapDrawable)new SoftReference(new BitmapDrawable(bitmap)).Get(), bitmap.Width, bitmap.Height); } } static int getFitInSampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options) { int inSampleSize = 1; if (options.OutWidth > reqWidth || options.OutHeight > reqHeight) { int widthRatio = (int)Math.Round(options.OutWidth * 1.0 / reqWidth); int heightRatio = (int)Math.Round(options.OutHeight * 1.0 / reqHeight); inSampleSize = Math.Min(widthRatio, heightRatio); } return inSampleSize; } } /// /// 点击时基本参数 /// public class MouseEventArgs : EventArgs { /// /// X坐标 /// public float X; /// /// Y坐标 /// public float Y; } public class AndroidView { //是否是活动状态 public static bool IsLive(Android.Views.View view) { return view.Enabled && view.Visibility == ViewStates.Visible && 0 < view.Alpha; } } }