工厂要求编写一个小系统,最后领导要求在程序界面上增加一个帮助功能,可以显示出每个按钮的作用,我在网上找了很多的资料,不过好像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周围生成一个矩形框,在下面会写出功能描述。
不过这个程序还很粗糙,暂时不能在引导界面中动态显示动画,只能显示静态的文字描述。