Xamarin Android 使用 ImageView实现帮助引导功能

原创 2018年04月16日 08:07:28

工厂要求编写一个小系统,最后领导要求在程序界面上增加一个帮助功能,可以显示出每个按钮的作用,我在网上找了很多的资料,不过好像Xamarin平台的资料不多,而且可以第三方例库也没有找到太好用的,就开始自己想,以下就是程序实现:

    class Guider:ImageView 
    {
        Context context;

        Bitmap BackgroudBitmap;
        Bitmap RefreshBitmap;

        private View[] ViewList;
        private int GuiderCount;
        private int CurrentGuider;

        private string[] OPDescription;
        private double TextLineLimit = 20;
        private int DrscriptionTextSize=80;

        private IOnGuiderErrorListener mListener;

        public Guider(Context context, View[] viewList, string[] opDescription,IOnGuiderErrorListener mListener) : base(context)
        {
            this.context = context;
            this.mListener = mListener;

            this.OPDescription = opDescription;
            this.ViewList = viewList;
            this.GuiderCount = viewList.Length-1;
            CurrentGuider = 0;

            this.LayoutParameters = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
            this.SetScaleType(ScaleType.FitXy);
        }

        /// <summary>
        /// 初始化加载视图
        /// </summary>
        /// <returns></returns>
        private bool InitGuiderBitmap()
        {
            try
            {
                if (RefreshBitmap == null) { RefreshBitmap = BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.RefreshGuider); }
                if (BackgroudBitmap == null) {  BackgroudBitmap= BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.Backgroud); }

                return true;
            }
            catch (System.Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 显示Gudier
        /// </summary>
        public bool ShowGudier()
        {
            try
            {
                if (!InitGuiderBitmap()) { return false; }

                if (CurrentGuider < 0 || CurrentGuider > GuiderCount) { return false; }

                Bitmap bitmap = BackgroudBitmap.Copy(Bitmap.Config.Alpha8, true);

                SetImageBitmap(bitmap);
                return true;
            }
            catch (System.Exception ex)
            {
                mListener.ErrorMessage("ShowGuider,"+ex.Message);
                CurrentGuider = -1;
                return false;
            }
        }

        /// <summary>
        /// 重绘事件
        /// </summary>
        /// <param name="canvas"></param>
        protected override void OnDraw(Canvas canvas)
        {
            //base.Draw(canvas);

            //在指定控件周围画出方框
            bool Result= DrawRectBitmap(canvas);
            if (!Result) { return; }

            //在指定控件的周围画出描述信息
            Result=DrawDescriptionBitmap(canvas);
            if (!Result) { return; }

            //在指定位置画出点击继续的提醒
            Result = DrawRefreshBitmap(canvas);
            if (!Result) { return; }

            CurrentGuider += 1;
        }

        /// <summary>
        /// 在指定控件周围画出方框
        /// </summary>
        /// <param name="DestCanvas"></param>
        /// <returns></returns>
        private bool DrawRectBitmap(Canvas DestCanvas)
        {
            try
            {
                if (CurrentGuider<0|| CurrentGuider > GuiderCount) { return false; }

                Bitmap bitmap = BackgroudBitmap.Copy(Bitmap.Config.Alpha8, true);
                Canvas canvas = new Canvas(bitmap);

                Paint RPaint = new Paint();
                RPaint.Color = Color.ParseColor("#FFFFFF");
                RPaint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.SrcOut));

                Rect rect = new Rect();
                int[] position = new int[2];
                ViewList[CurrentGuider].GetLocationInWindow(position);

                rect.Left = position[0] - 20;
                rect.Top = position[1] - 20;
                rect.Right = position[0] + ViewList[0].Width + 20;
                rect.Bottom = position[1]+ ViewList[0].Height  + 20;

                canvas.DrawRect(rect, RPaint);

                Paint paint = new Paint();
                paint.Alpha = 200;
                Rect DestRect = new Rect(0, 0, Width, Height);

                DestCanvas.DrawBitmap(bitmap, null, DestRect, paint);
                canvas.Dispose();
                canvas = null;
                bitmap.Recycle();
                bitmap = null;
                System.GC.Collect();
                return true;
            }
            catch (System.Exception ex)
            {
                mListener.ErrorMessage("DrawRectBitmap," + ex.Message);
                CurrentGuider = -1;
                return false;
            }
        }

        /// <summary>
        /// 在指定控件的周围画出描述信息
        /// </summary>
        /// <param name="DestCanvas"></param>
        /// <returns></returns>
        private bool DrawDescriptionBitmap(Canvas DestCanvas)
        {
            try
            {
                if (CurrentGuider<0|| CurrentGuider > GuiderCount) { return false; }

                Paint TPaint = new Paint
                {
                    Color = Color.White,
                    TextSize = DrscriptionTextSize,
                    TextAlign = Paint.Align.Left
                };

                double TextLines = System.Math.Ceiling(OPDescription[CurrentGuider].Length / TextLineLimit);

                Rect rect = new Rect();
                if (TextLines > 1) { TPaint.GetTextBounds(OPDescription[CurrentGuider].ToCharArray(), 0, 20, rect); }
                else { TPaint.GetTextBounds(OPDescription[CurrentGuider].ToCharArray(), 0, OPDescription[CurrentGuider].Length, rect); }
                
                int[] position = new int[2];
                ViewList[CurrentGuider].GetLocationInWindow(position);

                int Tx = position[0] +100;
                if (Tx + rect.Width() > context.Resources.DisplayMetrics.WidthPixels) { Tx = context.Resources.DisplayMetrics.WidthPixels - rect.Width(); }
                int Ty = position[1] + ViewList[0].Height + 100;
                if (Ty >= context.Resources.DisplayMetrics.HeightPixels)
                {
                    if (TextLines > 1) { Ty = position[1] - 100 - Convert.ToInt32(TextLines * rect.Height()); }
                    else { Ty = position[1] - 100; }
                }
                
                if (TextLines > 1)
                {
                    for(int i=0;i<TextLines;i++)
                    {
                        string txt = "";
                        if (i == ((int)TextLines - 1)) { txt = OPDescription[CurrentGuider].Substring(Convert.ToInt32(i * TextLineLimit)); }
                        else { txt = OPDescription[CurrentGuider].Substring(Convert.ToInt32(i * TextLineLimit), (int)TextLineLimit); }
                        
                        Ty += i * rect.Height();
                        DestCanvas.DrawText(txt, Tx, Ty, TPaint);
                    }
                }
                else { DestCanvas.DrawText(OPDescription[CurrentGuider], Tx, Ty, TPaint); }
                
                TPaint.Dispose();
                TPaint = null;
                return true;
            }
            catch (System.Exception ex)
            {
                mListener.ErrorMessage("DrawDescriptionBitmap,"+ex.Message);
                CurrentGuider = -1;
                return false;
            }
        }

        /// <summary>
        /// 在指定位置画出点击继续的提醒
        /// </summary>
        /// <param name="DestCanvas"></param>
        /// <returns></returns>
        private bool DrawRefreshBitmap(Canvas DestCanvas)
        {
            try
            {
                if (CurrentGuider < 0 || CurrentGuider > GuiderCount) { return false; }

                Paint TPaint = new Paint();
                TPaint.Color = Color.White;
                TPaint.TextSize = 60;
                TPaint.TextAlign = Paint.Align.Left;

                int Tx = context.Resources.DisplayMetrics.WidthPixels - 400;
                int Ty = context.Resources.DisplayMetrics.HeightPixels - 100;

                DestCanvas.DrawBitmap(RefreshBitmap, Tx - 100, Ty - 70, TPaint);
                DestCanvas.DrawText("点击屏幕继续!", Tx, Ty, TPaint);

                TPaint.Dispose();
                TPaint = null;
                return true;
            }
            catch (System.Exception ex)
            {
                mListener.ErrorMessage("DrawRefreshBitmap,"+ex.Message);
                CurrentGuider = -1;
                return false;
            }
        }

        /// <summary>
        /// 销毁进程
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            if (BackgroudBitmap != null) { BackgroudBitmap.Recycle(); BackgroudBitmap.Dispose(); BackgroudBitmap = null; }
            if (RefreshBitmap != null) { RefreshBitmap.Recycle(); RefreshBitmap.Dispose(); RefreshBitmap = null; }

            base.Dispose(disposing);
        }


        public interface IOnGuiderErrorListener
        {
            void ErrorMessage(string s);
        }

    }

以下为主程序调用:

    [Activity(Label = "App11", MainLauncher = true, Icon = "@mipmap/icon", Theme = "@android:style/Theme.Material.Light.NoActionBar.Fullscreen")]
    public class MainActivity : Activity
    {
        int count = 1;
        Guider guider;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            Button button = FindViewById<Button>(Resource.Id.myButton);
            View v = FindViewById<View>(Resource.Id.button1);
            View v1 = FindViewById<View>(Resource.Id.textView1);
            View v3 = FindViewById<View>(Resource.Id.checkBox5);
            button.Click += delegate {
                View view = FindViewById<View>(Resource.Id.linearLayout1);
                IViewParent viewParent = view.Parent;
                guider = new Guider(this, new View[] { v, v1,v3 }, new string[] { "这是一句很长很长的描述信息,需要测试是否可以自动分行显示啊!", "text2","test3" },new GuiderErrorMessage(this));
                if (viewParent is FrameLayout)
                {
                    FrameLayout frameLayout = (FrameLayout)viewParent;
                                      
                    frameLayout.AddView(guider);
                    guider.ShowGudier();
                    
                    guider.Click += (object sender, System.EventArgs e) =>
                    {
                        if (!guider.ShowGudier()) { frameLayout.RemoveView(guider);guider.Dispose(); }
                    };
                }
            };
        }

        public class GuiderErrorMessage : Guider.IOnGuiderErrorListener
        {
            MainActivity mainActivity;
            public GuiderErrorMessage(MainActivity context)
            {
                this.mainActivity = context;
            }
            public void ErrorMessage(string s)
            {
                //throw new System.NotImplementedException();
                Toast.MakeText(mainActivity, s, ToastLength.Short).Show();
            }
        }

    }

以上为主程序布局图:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/frameLayout1">
    <LinearLayout
        android:orientation="vertical"
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/linearLayout1">
        <Button
            android:id="@+id/myButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello" />
        <TextView
            android:text="Text"
            android:textSize="40dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/textView1" />
        <LinearLayout
            android:orientation="vertical"
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/linearLayout2">
            <Button
                android:text="Button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/button1" />
        </LinearLayout>
        <LinearLayout
            android:orientation="horizontal"
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/linearLayout3">
            <CheckBox
                android:text="CheckBox"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:id="@+id/checkBox2" />
            <CheckBox
                android:text="CheckBox"
                android:gravity="left"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/checkBox1" />
            <CheckBox
                android:text="CheckBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/checkBox3" />
            <CheckBox
                android:text="CheckBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/checkBox5" />
        </LinearLayout>
    </LinearLayout>
</FrameLayout>

这个帮助引导界面会自动在需要写的VIEW周围生成一个矩形框,在下面会写出功能描述。

不过这个程序还很粗糙,暂时不能在引导界面中动态显示动画,只能显示静态的文字描述。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xml398641805/article/details/79955731

Xamarin.Android 如何使用圆形Image

几个月没有更博了,惭愧惭愧,新年到了,给大家拜个年,也希望自己在新的一年里面努力学技术,当好一枚程序媛! 在做App UI的过程中发现圆形Image很有用,但是呢自己又不会写,在网上找了找资源,...
  • sinat_26562875
  • sinat_26562875
  • 2016年02月14日 16:26
  • 891

Xamarin Android Circle ImageView 圆形图片实现

Xamarin Android Circle ImageView 圆形图片实现参考:http://www.cnblogs.com/mycing/p/5556943.html根据上面的文章,自己写了个列...
  • cctvcqupt
  • cctvcqupt
  • 2016年08月24日 17:14
  • 518

JQuery插件实现网页首次登录提示/页面功能介绍引导/教程式引导/下一步介绍功能

因某个单独网页中的功能较多,或者按钮提示较多,为方便用户更了解页面功能...
  • chenkai6529
  • chenkai6529
  • 2014年08月27日 16:55
  • 2698

Android 操作引导功能

在我们开发一个新的应用程序或者对一个应用程序进行迭代改动较大时,大多数APP都会在用户第一次使用这些新功能的时候,通过一定的方法来告诉、指导用户发现、使用这些新的功能,而这个方法就是操作引导。通常情况...
  • ITRenj
  • ITRenj
  • 2016年12月26日 22:32
  • 2580

关于android新手引导的开源使用

做APP的时候难免用到新手引导的效果。 先放一张效果的图片吧。虽然丑了点,讲究实用吧。 本人在开发的时候,使用了github这位同学的开源代码,这里推荐一下开源的githu...
  • qq_21139343
  • qq_21139343
  • 2017年01月18日 14:57
  • 1471

用Imageview实现复选框效果

今天在看前人写的代码时,实现用Imageview实现复选框效果,发现了一种自己以前没有尝试过的写法,还了解了Imageview的getConstantState()方法; 值得学习的是---...
  • u010184528
  • u010184528
  • 2017年05月09日 17:11
  • 371

C# + Xamarin开发Android应用 --- Tab的实现

C# + Xamarin开发Android应用 --- Tab的实现
  • csharp25
  • csharp25
  • 2015年05月19日 18:10
  • 2401

android(2) 功能引导界面实现

一.界面实现:      记录下引导界面的实现,总体来说实现不算困难,前提是要有个美工帮你做这些引导图片:...
  • u010708662
  • u010708662
  • 2015年05月20日 09:27
  • 1794

[Android]新功能引导高亮显示遮罩层View

[Android]新功能引导高亮显示遮罩层View@Author GQ 2016年08月5日 实际上是一个Activity遮盖在目标View的上方, 可以设置遮罩层文字图片等,亲测好使。原文git...
  • baidu_25797177
  • baidu_25797177
  • 2016年08月05日 10:37
  • 2796

Xamarin 技术全解析

Xamarin 是一套基于C#语言的跨平台移动应用开发工具,今年2月份微软宣布收购Xamarin,而后在4月份进行的Build大会上微软宣布将会在各个版本的Visual Studio中免费提供Xama...
  • powertoolsteam
  • powertoolsteam
  • 2016年05月25日 10:12
  • 5164
收藏助手
不良信息举报
您举报文章:Xamarin Android 使用 ImageView实现帮助引导功能
举报原因:
原因补充:

(最多只允许输入30个字)