GuideView的封裝實(shí)現(xiàn)app功能引導(dǎo)頁(yè)
本文實(shí)例為大家分享了GuideView的封裝實(shí)現(xiàn)app功能引導(dǎo)頁(yè)的具體代碼,供大家參考,具體內(nèi)容如下
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第一次打開(kāi)功能蒙版 引導(dǎo) */ 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; /** * 透明圓形畫(huà)筆 */ private Paint mCirclePaint; /** * 背景色畫(huà)筆 */ private Paint mBackgroundPaint; /** * targetView是否已測(cè)量 */ private boolean isMeasured; /** * targetView圓心 */ private int[] center; /** * 繪圖層疊模式 */ private PorterDuffXfermode porterDuffXfermode; /** * 繪制前景bitmap */ private Bitmap bitmap; /** * 背景色和透明度,格式 #aarrggbb */ private int backgroundColor; /** * Canvas,繪制bitmap */ private Canvas temp; /** * 相對(duì)于targetView的位置.在target的那個(gè)方向 */ private Direction direction; /** * 形狀 */ private MyShape myShape; /** * targetView左上角坐標(biāo) */ 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的下邊 * 在屏幕窗口,添加蒙層,蒙層繪制總背景和透明圓形,圓形下邊繪制說(shuō)明文字 */ private void createGuideView() { Log.v(TAG, "createGuideView"); // 添加到蒙層 // if (guideViewLayout == null) { // guideViewLayout = new RelativeLayout(mContent); // } // Tips布局參數(shù) 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 的寬高,如果未測(cè)量,返回{-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); // 背景畫(huà)筆 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 的透明圓形畫(huà)筆 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對(duì)象 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對(duì)象 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的中心坐標(biāo) if (center == null) { // 獲取右上角坐標(biāo) location = new int[2]; targetView.getLocationInWindow(location); center = new int[2]; // 獲取中心坐標(biāo) center[0] = location[0] + targetView.getWidth() / 2; center[1] = location[1] + targetView.getHeight() / 2; } // 獲取targetView外切圓半徑 if (radius == 0) { radius = getTargetViewRadius(); } // 添加GuideView createGuideView(); } /** * 定義GuideView相對(duì)于targetView的方位,共八種。不設(shè)置則默認(rèn)在targetView下方 */ enum Direction { LEFT, TOP, RIGHT, BOTTOM, LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM } /** * 定義目標(biāo)控件的形狀,共3種。圓形,橢圓,帶圓角的矩形(可以設(shè)置圓角大?。?,不設(shè)置則默認(rèn)是圓形 */ enum MyShape { CIRCULAR, ELLIPSE, RECTANGULAR } /** * GuideView點(diǎn)擊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; } } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android客戶端首次啟動(dòng)引導(dǎo)界面
- android使用ViewPager組件實(shí)現(xiàn)app引導(dǎo)查看頁(yè)面
- Android繪制炫酷的引導(dǎo)界面
- Android引導(dǎo)頁(yè)面的簡(jiǎn)單實(shí)現(xiàn)
- Android自定義View實(shí)現(xiàn)水波紋引導(dǎo)動(dòng)畫(huà)
- android 引導(dǎo)界面的實(shí)現(xiàn)方法
- Android使用ViewPager實(shí)現(xiàn)啟動(dòng)引導(dǎo)頁(yè)
- Android開(kāi)發(fā)實(shí)戰(zhàn)之漂亮的ViewPager引導(dǎo)頁(yè)
- Android GuideView實(shí)現(xiàn)首次登陸引導(dǎo)
相關(guān)文章
Kotlin?Navigation可視化開(kāi)發(fā)詳解
Navigation?是?JetPack?中的一個(gè)組件,用于方便的實(shí)現(xiàn)頁(yè)面的導(dǎo)航,所以抽象出了一個(gè)?destination?的概念,大部分情況一個(gè)?destination?就表示一個(gè)?Fragment,但是它同樣可以指代?Activity、其它的導(dǎo)航圖2023-02-02Android實(shí)現(xiàn)長(zhǎng)圖展開(kāi)與收起效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)長(zhǎng)圖展開(kāi)與收起效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09Android自定義FloatingActionButton滑動(dòng)行為只隱藏不出現(xiàn)的問(wèn)題小結(jié)
這篇文章主要介紹了Android自定義FloatingActionButton滑動(dòng)行為只隱藏不出現(xiàn)的問(wèn)題小結(jié),需要的朋友可以參考下2017-01-01Android開(kāi)發(fā)實(shí)現(xiàn)NFC刷卡讀取的兩種方式
這篇文章主要為大家詳細(xì)介紹了Android開(kāi)發(fā)中實(shí)現(xiàn)NFC刷卡讀取的兩種方式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09準(zhǔn)確測(cè)量 Android 應(yīng)用中 Activity 和 Fragmen
在 Android 應(yīng)用開(kāi)發(fā)中,了解每個(gè) Activity 和 Fragment 的啟動(dòng)時(shí)間對(duì)于性能優(yōu)化至關(guān)重要,本文將介紹幾種方法來(lái)準(zhǔn)確測(cè)量 Activity 和 Fragment 的啟動(dòng)時(shí)間,并提供實(shí)際操作步驟,以幫助提升應(yīng)用的響應(yīng)速度和用戶體驗(yàn),需要的朋友可以參考下2024-07-07Kotlin注解實(shí)現(xiàn)Parcelable序列化流程詳解
有時(shí)我們會(huì)在界面跳轉(zhuǎn)的過(guò)程中,做對(duì)象傳值,這時(shí)就需要對(duì)該對(duì)象做序列化處理了。Android中對(duì)對(duì)象的序列化處理有兩種方式,這篇文章主要介紹了Kotlin注解實(shí)現(xiàn)Parcelable序列化2022-12-12圖解Windows環(huán)境下Android Studio安裝和使用教程
這篇文章主要介紹了圖解Windows環(huán)境下Android Studio安裝和使用教程的相關(guān)資料,需要的朋友可以參考下2015-12-12Android?Studio打包?aar實(shí)現(xiàn)步驟示例詳解
這篇文章主要為大家介紹了Android?Studio打包aar步驟示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08