1. 程式人生 > >Android 新手引導半透明蒙層效果實現

Android 新手引導半透明蒙層效果實現

效果圖:

其中的文字和我知道啦是ui切得兩張透明圖片
自定義View:

package com.cymobi.library.view.widget;

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.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 com.cymobi.library.R; /** * Created by xuke on 2017/8/24. */
public class GuideView extends RelativeLayout implements ViewTreeObserver.OnGlobalLayoutListener { private final String TAG = getClass().getSimpleName(); private Context mContent; private boolean first = true; private static final String SHOW_GUIDE_PREFIX = "show_guide"; private
int offsetX, offsetY; private int radius; private View targetView; private View textGuideView; private View customGuideView; private Paint mCirclePaint; private Paint mBackgroundPaint; private boolean isMeasured; private int[] center; private PorterDuffXfermode porterDuffXfermode; private Bitmap bitmap; private int backgroundColor; private Canvas temp; private Direction direction; private MyShape myShape; private int[] location; private boolean onClickExit; private OnClickCallback onclickListener; private int targetViewWidth; private int targetViewHeight; private boolean isContain = false; private boolean needDraw = true; public GuideView(Context context) { super(context); this.mContent = context; } public int[] getLocation() { return location; } public void setLocation(int[] location) { this.location = location; } public int getRadius() { return radius; } public void setRadius(int radius) { this.radius = radius; } public void setDirection(Direction direction) { this.direction = direction; } public void setShape(MyShape shape) { this.myShape = shape; } public void setBgColor(int background_color) { this.backgroundColor = background_color; } public void setTargetView(View targetView) { this.targetView = targetView; } public int[] getCenter() { return center; } public void setCenter(int[] center) { this.center = center; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } public void setContain(boolean contain) { this.isContain = contain; } public void setCustomGuideView(View customGuideView) { this.customGuideView = customGuideView; if (!first) { restoreState(); } } public void setTextGuideView(View textGuideView) { this.textGuideView = textGuideView; if (!first) { restoreState(); } } 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 void setOnclickListener(OnClickCallback onclickListener) { this.onclickListener = onclickListener; } private void setClickInfo() { final boolean exit = onClickExit; setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (onclickListener != null) { onclickListener.onClickedGuideView(); } if (exit) { hide(); } } }); } public void show() { Log.v(TAG, "show"); if (hasShown()) return; if (targetView != null) { targetView.getViewTreeObserver().addOnGlobalLayoutListener(this); } this.setBackgroundResource(R.color.transparent); this.bringToFront(); //設定在最上層 ((FrameLayout) ((Activity) mContent).getWindow().getDecorView()).addView(this); first = false; } public void hide() { Log.v(TAG, "hide"); if (customGuideView != null || textGuideView != null) { targetView.getViewTreeObserver().removeOnGlobalLayoutListener(this); this.removeAllViews(); ((FrameLayout) ((Activity) mContent).getWindow().getDecorView()).removeView(this); restoreState(); } } /** * 獲得targetView 的寬高 * * @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; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.v(TAG, "onDraw"); if (!isMeasured) return; if (targetView == null) 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.bg_shadow)); } // 繪製螢幕背景 temp.drawRect(0, 0, temp.getWidth(), temp.getHeight(), bgPaint); // targetView 的透明圓形畫筆 if (mCirclePaint == null) { mCirclePaint = new Paint(); } //透明效果 porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR); //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 RECTANGULAR://圓角矩形 if (isContain) { oval.left = location[0] - 8; oval.top = center[1] - targetViewHeight / 2 - 8; oval.right = location[0] + targetViewWidth + 8; oval.bottom = center[1] + targetViewHeight / 2 + 8; } else { oval.left = location[0] + 5; oval.top = center[1] - targetViewHeight / 2 + 1; oval.right = location[0] + targetViewWidth - 5; oval.bottom = center[1] + targetViewHeight / 2 - 1; } temp.drawRoundRect(oval, radius, radius, mCirclePaint); break; } } else { temp.drawCircle(center[0], center[1], radius, mCirclePaint); } // 繪製到螢幕 canvas.drawBitmap(bitmap, 0, 0, bgPaint); bitmap.recycle(); } @Override public void onGlobalLayout() { if (isMeasured) return; if (targetView.getHeight() > 0 && targetView.getWidth() > 0) { isMeasured = true; targetViewWidth = targetView.getWidth(); targetViewHeight = targetView.getHeight(); } // 獲取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(); } //文字圖片和提示圖片 createView(); } //文字圖片和我知道啦圖片一起放 private void createView() { Log.v(TAG, "createView"); //文字提示 LayoutParams textViewParams; textViewParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); textViewParams.setMargins(0, center[1] + radius + 10, 0, 0); // 我知道提示佈局引數 LayoutParams guideViewParams; guideViewParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); guideViewParams.setMargins(0, center[1] + radius + 10, 0, 0); if (textGuideView != null && customGuideView != null) { if (direction != null) { int left = center[0] + targetViewWidth / 2; int right = center[0] + targetViewWidth / 2; int top = center[1] - targetViewHeight / 2; int bottom = center[1] + targetViewHeight / 2; //我自己的專案只需要這兩個方向的, 所以這裡就只寫了Top和Boottom switch (direction) { case TOP: this.setGravity(Gravity.CENTER_HORIZONTAL); textViewParams.setMargins(offsetX, top - offsetY, -offsetX, -top + offsetY); guideViewParams.setMargins(offsetX, -3 * offsetY + top, -offsetX, -top + 3 * offsetY); break; case BOTTOM: this.setGravity(Gravity.CENTER_HORIZONTAL); textViewParams.setMargins(offsetX, bottom + offsetY, -offsetX, -bottom - offsetY); guideViewParams.setMargins(offsetX, bottom + 3 * offsetY, -offsetX, -bottom - 3 * offsetY); break; } if (this != null) this.removeAllViews(); this.addView(textGuideView, textViewParams); this.addView(customGuideView, guideViewParams); } } } /** * 定義GuideView相對於targetView的方位, */ public enum Direction { LEFT, TOP, RIGHT, BOTTOM, LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM } /** * 定義目標控制元件的形狀。圓形,矩形 */ public enum MyShape { CIRCULAR, RECTANGULAR } /** * GuideView點選Callback */ public 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; } /** * 設定目標view */ public Builder setTargetView(View target) { guiderView.setTargetView(target); return instance; } /** * 設定蒙層顏色 */ public Builder setBgColor(int color) { guiderView.setBgColor(color); return instance; } /** * 設定文字和圖片View 在目標view的位置 */ public Builder setDirction(Direction dir) { guiderView.setDirection(dir); return instance; } /** * 設定繪製形狀 */ public Builder setShape(MyShape shape) { guiderView.setShape(shape); return instance; } public Builder setRadius(int radius) { guiderView.setRadius(radius); return instance; } /** * 設定文字圖片 */ public Builder setTextGuideView(View view) { guiderView.setTextGuideView(view); return instance; } /** * 設定"我知道啦"圖片 */ public Builder setCustomGuideView(View view) { guiderView.setCustomGuideView(view); return instance; } /** * 設定圖片的偏移量 */ public Builder setOffset(int x, int y) { guiderView.setOffsetX(x); guiderView.setOffsetY(y); return instance; } /** * 設定時候包含 true:畫的透明包含目標view */ public Builder setContain(boolean isContain) { guiderView.setContain(isContain); return instance; } /** * 點選監聽 */ public Builder setOnclickListener(final OnClickCallback callback) { guiderView.setOnclickListener(callback); return instance; } public GuideView build() { guiderView.setClickInfo(); return guiderView; } } 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; temp = null; } }

在自己頁面應用:

        //文字圖片
        final ImageView iv1 = new ImageView(context);
        iv1.setImageResource(R.drawable.img_guide_work_text);
        RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        iv1.setLayoutParams(params1);

        //我知道啦
        final ImageView iv2 = new ImageView(context);
        iv2.setImageResource(R.drawable.img_guide_know);
        RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        iv2.setLayoutParams(params2);

  guideView = GuideView.Builder
                .newInstance(context)
                .setTargetView(itemWork)  //設定目標view
                .setTextGuideView(iv1)      //設定文字圖片
                .setCustomGuideView(iv2)    //設定 我知道啦圖片
                .setOffset(0, 80)           //偏移量  x=0 y=80
                .setDirction(GuideView.Direction.BOTTOM)   //方向
                .setShape(GuideView.MyShape.RECTANGULAR)   //矩形
                .setRadius(10)                             //圓角
                .setContain(false)                         //透明的方塊時候包含目標view  預設false
                .setBgColor(getResources().getColor(R.color.bg_shadow))   //背景顏色
                .setOnclickListener(new GuideView.OnClickCallback() {
                    @Override
                    public void onClickedGuideView() {
                        guideView.hide();
                    }
                })
                .build();
  guideView.show();