本文实例为大家分享了GuideView的封装实现app功能引导页的具体代码,供大家参考,具体内容如下

package oschina.comxianbing100.yindao;
 
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
 
import java.util.List;
 
/**
 * author : Majunbao
 * date : 2019/3/4 16:32
 * description :App第一次打开功能蒙版 引导
 */
public class GuideView extends RelativeLayout implements ViewTreeObserver.OnGlobalLayoutListener {
 private final String TAG = getClass().getSimpleName();
 private Context mContent;
 private List<View> mViews;
 private boolean first = true;
 /**
  * targetView前缀。SHOW_GUIDE_PREFIX   targetView.getId()作为保存在SP文件的key。
  */
 private static final String SHOW_GUIDE_PREFIX = "show_guide_on_view_";
 /**
  * GuideView 偏移量
  */
 private int offsetX, offsetY;
 /**
  * targetView 的外切圆半径
  */
 private int radius;
 /**
  * 需要显示提示信息的View
  */
 private View targetView;
 /**
  * 自定义View
  */
 private View customGuideView;
 /**
  * 透明圆形画笔
  */
 private Paint mCirclePaint;
 /**
  * 背景色画笔
  */
 private Paint mBackgroundPaint;
 /**
  * targetView是否已测量
  */
 private boolean isMeasured;
 /**
  * targetView圆心
  */
 private int[] center;
 /**
  * 绘图层叠模式
  */
 private PorterDuffXfermode porterDuffXfermode;
 /**
  * 绘制前景bitmap
  */
 private Bitmap bitmap;
 /**
  * 背景色和透明度,格式 #aarrggbb
  */
 private int backgroundColor;
 /**
  * Canvas,绘制bitmap
  */
 private Canvas temp;
 /**
  * 相对于targetView的位置.在target的那个方向
  */
 private Direction direction;
 
 /**
  * 形状
  */
 private MyShape myShape;
 /**
  * targetView左上角坐标
  */
 private int[] location;
 private boolean onClickExit;
 private OnClickCallback onclickListener;
 private RelativeLayout guideViewLayout;
 
 public void restoreState() {
  Log.v(TAG, "restoreState");
  offsetX = offsetY = 0;
  radius = 0;
  mCirclePaint = null;
  mBackgroundPaint = null;
  isMeasured = false;
  center = null;
  porterDuffXfermode = null;
  bitmap = null;
  needDraw = true;
  //  backgroundColor = Color.parseColor("#00000000");
  temp = null;
  //  direction = null;
 
 }
 
 public int[] getLocation() {
  return location;
 }
 
 public void setLocation(int[] location) {
  this.location = location;
 }
 
 public GuideView(Context context) {
  super(context);
  this.mContent = context;
  init();
 }
 
 public int getRadius() {
  return radius;
 }
 
 public void setRadius(int radius) {
  this.radius = radius;
 }
 
 public void setOffsetX(int offsetX) {
  this.offsetX = offsetX;
 }
 
 public void setOffsetY(int offsetY) {
  this.offsetY = offsetY;
 }
 
 public void setDirection(Direction direction) {
  this.direction = direction;
 }
 
 public void setShape(MyShape shape) {
  this.myShape = shape;
 }
 
 public void setCustomGuideView(View customGuideView) {
  this.customGuideView = customGuideView;
  if (!first) {
   restoreState();
  }
 }
 
 public void setBgColor(int background_color) {
  this.backgroundColor = background_color;
 }
 
 public View getTargetView() {
  return targetView;
 }
 
 public void setTargetView(View targetView) {
  this.targetView = targetView;
  //  restoreState();
  if (!first) {
   //   guideViewLayout.removeAllViews();
  }
 }
 
 private void init() {
 }
 
 public void showOnce() {
  if (targetView != null) {
   mContent.getSharedPreferences(TAG, Context.MODE_PRIVATE).edit().putBoolean(generateUniqId(targetView), true).commit();
  }
 }
 
 private boolean hasShown() {
  if (targetView == null)
   return true;
  return mContent.getSharedPreferences(TAG, Context.MODE_PRIVATE).getBoolean(generateUniqId(targetView), false);
 }
 
 private String generateUniqId(View v) {
  return SHOW_GUIDE_PREFIX   v.getId();
 }
 
 public int[] getCenter() {
  return center;
 }
 
 public void setCenter(int[] center) {
  this.center = center;
 }
 
 @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
 public void hide() {
  Log.v(TAG, "hide");
  if (customGuideView != null) {
   targetView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
   this.removeAllViews();
   ((FrameLayout) ((Activity) mContent).getWindow().getDecorView()).removeView(this);
   restoreState();
  }
 }
 
 public void show() {
  Log.v(TAG, "show");
  if (hasShown())
   return;
 
  if (targetView != null) {
   targetView.getViewTreeObserver().addOnGlobalLayoutListener(this);
  }
 
  this.setBackgroundResource(R.color.transparent);
 
  ((FrameLayout) ((Activity) mContent).getWindow().getDecorView()).addView(this);
  first = false;
 }
 
 /**
  * 添加提示文字,位置在targetView的下边
  * 在屏幕窗口,添加蒙层,蒙层绘制总背景和透明圆形,圆形下边绘制说明文字
  */
 private void createGuideView() {
  Log.v(TAG, "createGuideView");
 
  // 添加到蒙层
  //  if (guideViewLayout == null) {
  //   guideViewLayout = new RelativeLayout(mContent);
  //  }
 
  // Tips布局参数
  LayoutParams guideViewParams;
  guideViewParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
  guideViewParams.setMargins(0, center[1]   radius   10, 0, 0);
 
  if (customGuideView != null) {
 
   //   LayoutParams guideViewParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
   if (direction != null) {
    int width = this.getWidth();
    int height = this.getHeight();
 
    int left = center[0] - radius;
    int right = center[0]   radius;
    int top = center[1] - radius;
    int bottom = center[1]   radius;
    switch (direction) {
     case TOP:
      this.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
      guideViewParams.setMargins(offsetX, offsetY - height   top, -offsetX, height - top - offsetY);
      break;
     case LEFT:
      this.setGravity(Gravity.RIGHT);
      guideViewParams.setMargins(offsetX - width   left, top   offsetY, width - left - offsetX, -top - offsetY);
      break;
     case BOTTOM:
      this.setGravity(Gravity.CENTER_HORIZONTAL);
      guideViewParams.setMargins(offsetX, bottom   offsetY, -offsetX, -bottom - offsetY);
      break;
     case RIGHT:
      guideViewParams.setMargins(right   offsetX, top   offsetY, -right - offsetX, -top - offsetY);
      break;
     case LEFT_TOP:
      this.setGravity(Gravity.RIGHT | Gravity.BOTTOM);
      guideViewParams.setMargins(offsetX - width   left, offsetY - height   top, width - left - offsetX, height - top - offsetY);
      break;
     case LEFT_BOTTOM:
      this.setGravity(Gravity.RIGHT);
      guideViewParams.setMargins(offsetX - width   left, bottom   offsetY, width - left - offsetX, -bottom - offsetY);
      break;
     case RIGHT_TOP:
      this.setGravity(Gravity.BOTTOM);
      guideViewParams.setMargins(right   offsetX, offsetY - height   top, -right - offsetX, height - top - offsetY);
      break;
     case RIGHT_BOTTOM:
      guideViewParams.setMargins(right   offsetX, bottom   offsetY, -right - offsetX, -top - offsetY);
      break;
    }
   } else {
    guideViewParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    guideViewParams.setMargins(offsetX, offsetY, -offsetX, -offsetY);
   }
 
   //   guideViewLayout.addView(customGuideView);
 
   this.addView(customGuideView, guideViewParams);
  }
 }
 
 /**
  * 获得targetView 的宽高,如果未测量,返回{-1, -1}
  *
  * @return
  */
 private int[] getTargetViewSize() {
  int[] location = {-1, -1};
  if (isMeasured) {
   location[0] = targetView.getWidth();
   location[1] = targetView.getHeight();
  }
  return location;
 }
 
 /**
  * 获得targetView 的半径
  *
  * @return
  */
 private int getTargetViewRadius() {
  if (isMeasured) {
   int[] size = getTargetViewSize();
   int x = size[0];
   int y = size[1];
 
   return (int) (Math.sqrt(x * x   y * y) / 2);
  }
  return -1;
 }
 
 boolean needDraw = true;
 
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  Log.v(TAG, "onDraw");
 
  if (!isMeasured)
   return;
 
  if (targetView == null)
   return;
 
  //  if (!needDraw) return;
 
  drawBackground(canvas);
 
 }
 
 private void drawBackground(Canvas canvas) {
  Log.v(TAG, "drawBackground");
  needDraw = false;
  // 先绘制bitmap,再将bitmap绘制到屏幕
  bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
  temp = new Canvas(bitmap);
 
  // 背景画笔
  Paint bgPaint = new Paint();
  if (backgroundColor != 0)
   bgPaint.setColor(backgroundColor);
  else
   bgPaint.setColor(getResources().getColor(R.color.shadow));
 
  // 绘制屏幕背景
  temp.drawRect(0, 0, temp.getWidth(), temp.getHeight(), bgPaint);
 
  // targetView 的透明圆形画笔
  if (mCirclePaint == null)
   mCirclePaint = new Paint();
  porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT);// 或者CLEAR
  mCirclePaint.setXfermode(porterDuffXfermode);
  mCirclePaint.setAntiAlias(true);
 
  if (myShape != null) {
   RectF oval = new RectF();
   switch (myShape) {
    case CIRCULAR://圆形
     temp.drawCircle(center[0], center[1], radius, mCirclePaint);//绘制圆形
     break;
    case ELLIPSE://椭圆
     //RectF对象
     oval.left = center[0] - 150;        //左边
     oval.top = center[1] - 50;         //上边
     oval.right = center[0]   150;        //右边
     oval.bottom = center[1]   50;        //下边
     temp.drawOval(oval, mCirclePaint);     //绘制椭圆
     break;
    case RECTANGULAR://圆角矩形
     //RectF对象
     oval.left = center[0] - 150;        //左边
     oval.top = center[1] - 50;         //上边
     oval.right = center[0]   150;        //右边
     oval.bottom = center[1]   50;        //下边
     temp.drawRoundRect(oval, radius, radius, mCirclePaint);     //绘制圆角矩形
     break;
   }
  } else {
   temp.drawCircle(center[0], center[1], radius, mCirclePaint);//绘制圆形
  }
 
  // 绘制到屏幕
  canvas.drawBitmap(bitmap, 0, 0, bgPaint);
  bitmap.recycle();
 }
 
 public void setOnClickExit(boolean onClickExit) {
  this.onClickExit = onClickExit;
 }
 
 public void setOnclickListener(OnClickCallback onclickListener) {
  this.onclickListener = onclickListener;
 }
 
 private void setClickInfo() {
  final boolean exit = onClickExit;
  setOnClickListener(new OnClickListener() {
   @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
   @Override
   public void onClick(View v) {
    if (onclickListener != null) {
     onclickListener.onClickedGuideView();
    }
    if (exit) {
     hide();
    }
   }
  });
 }
 
 @Override
 public void onGlobalLayout() {
  if (isMeasured)
   return;
  if (targetView.getHeight() > 0 && targetView.getWidth() > 0) {
   isMeasured = true;
  }
 
  // 获取targetView的中心坐标
  if (center == null) {
   // 获取右上角坐标
   location = new int[2];
   targetView.getLocationInWindow(location);
   center = new int[2];
   // 获取中心坐标
   center[0] = location[0]   targetView.getWidth() / 2;
   center[1] = location[1]   targetView.getHeight() / 2;
  }
  // 获取targetView外切圆半径
  if (radius == 0) {
   radius = getTargetViewRadius();
  }
  // 添加GuideView
  createGuideView();
 }
 
 /**
  * 定义GuideView相对于targetView的方位,共八种。不设置则默认在targetView下方
  */
 enum Direction {
  LEFT, TOP, RIGHT, BOTTOM,
  LEFT_TOP, LEFT_BOTTOM,
  RIGHT_TOP, RIGHT_BOTTOM
 }
 
 /**
  * 定义目标控件的形状,共3种。圆形,椭圆,带圆角的矩形(可以设置圆角大小),不设置则默认是圆形
  */
 enum MyShape {
  CIRCULAR, ELLIPSE, RECTANGULAR
 }
 
 /**
  * GuideView点击Callback
  */
 interface OnClickCallback {
  void onClickedGuideView();
 }
 
 public static class Builder {
  static GuideView guiderView;
  static Builder instance = new Builder();
  Context mContext;
 
  private Builder() {
  }
 
  public Builder(Context ctx) {
   mContext = ctx;
  }
 
  public static Builder newInstance(Context ctx) {
   guiderView = new GuideView(ctx);
   return instance;
  }
 
  public Builder setTargetView(View target) {
   guiderView.setTargetView(target);
   return instance;
  }
 
  public Builder setBgColor(int color) {
   guiderView.setBgColor(color);
   return instance;
  }
 
  public Builder setDirction(Direction dir) {
   guiderView.setDirection(dir);
   return instance;
  }
 
  public Builder setShape(MyShape shape) {
   guiderView.setShape(shape);
   return instance;
  }
 
  public Builder setOffset(int x, int y) {
   guiderView.setOffsetX(x);
   guiderView.setOffsetY(y);
   return instance;
  }
 
  public Builder setRadius(int radius) {
   guiderView.setRadius(radius);
   return instance;
  }
 
  public Builder setCustomGuideView(View view) {
   guiderView.setCustomGuideView(view);
   return instance;
  }
 
  public Builder setCenter(int X, int Y) {
   guiderView.setCenter(new int[]{X, Y});
   return instance;
  }
 
  public Builder showOnce() {
   guiderView.showOnce();
   return instance;
  }
 
  public GuideView build() {
   guiderView.setClickInfo();
   return guiderView;
  }
 
  public Builder setOnclickExit(boolean onclickExit) {
   guiderView.setOnClickExit(onclickExit);
   return instance;
  }
 
  public Builder setOnclickListener(final OnClickCallback callback) {
   guiderView.setOnclickListener(callback);
   return instance;
  }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

GuideView的封装实现app功能引导页的更多相关文章

  1. 详解如何通过H5(浏览器/WebView/其他)唤起本地app

    这篇文章主要介绍了详解如何通过H5(浏览器/WebView/其他)唤起本地app的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. H5混合开发app如何升级的方法

    本篇文章主要介绍了H5混合开发app如何升级的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. html5唤起app的方法

    这篇文章主要介绍了html5唤起app的方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. xcode – 上传到App Store时进行身份验证

    只需为现有安装/文件夹创建备份,这很重要,因为在(新)安装期间,Transporter将删除以前的安装:现在运行以下命令来更新Transporter:希望这有助于某人.

  5. App store拒绝应用程序在iOs 10上支持IPV6网络

    我收到苹果公司的app拒绝邮件,下面是我们在连接到IPv6网络的Wi-Fi上运行iOS10.0.2的iPad和iPhone上查看了应用中的一个或多个错误.具体来说,应用程序在启动时仍保留在启动屏根据他们的要求,我已经在我的Mac上创建了NAT64网络,并为iPhone5S设备10.0.2os版本共享了互联网,App工作正常,但苹果称其不与IPv6合作任何人都可以确认我需要检查其他什么吗?

  6. ios – 我如何从iPhone中提取IPA以从App Store下载以便我可以在IPA中查看资产?

    我最喜欢的应用程序之一已从应用程序商店中删除,我想因为它没有在太长时间内更新.我有一台旧设备,但没有下载到我的新手机上.如何获得IPA以便我可以查看应用程序包并查看应用程序中的资产?

  7. ios – – [Not A Type _cfTypeID]:发送到解除分配的实例的消息

    我正在使用代码为图像提供不同的效果,如对比度,色调,饱和度等;并使用了appleglImageProcessing代码,我从我的视图跳转到glimgeProcessing,并将结果图像保存到appDelegate文件中的uiimage属性.从Eagle视图返回后,我使用viewDidAppear函数将我的图像视图更改为更新的图像我的代码是我的日志响应是尝试将图像设置为我的imageView时出现问

  8. iOS扩展:是否需要增加其捆绑版本(CFBundleVersion)?

    我是否必须在我的扩展程序的Info.plist中增加CFBundLeversion以确保它覆盖现有的?或者,如果在主应用程序的Info.plist中这样做就足够了?

  9. ios – navigator.app undefined

    谢谢你的帮助.干杯,米格尔解决方法“navigator.app”对象仅适用于Android.幸运的是,在即将发布的PhoneGap2.3.0版本中你可以做到:做你想做的事.

  10. 验证Xcode安装时,“/Applications/Xcode.app:密封资源丢失或无效”错误

    你认为我需要重新安装Xcode以防万一?

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部