Commit c3a7ed9e authored by wanglei's avatar wanglei

..

parent 901ea090
...@@ -31,6 +31,9 @@ import com.base.scanqrclear.ui.telephone.TelephoneActivity ...@@ -31,6 +31,9 @@ import com.base.scanqrclear.ui.telephone.TelephoneActivity
import com.base.scanqrclear.ui.text.TextActivity import com.base.scanqrclear.ui.text.TextActivity
import com.base.scanqrclear.ui.website.WebsiteActivity import com.base.scanqrclear.ui.website.WebsiteActivity
import com.base.scanqrclear.ui.webview.WebBrowserActivity import com.base.scanqrclear.ui.webview.WebBrowserActivity
import com.base.scanqrclear.ui.widget.guideview.Component
import com.base.scanqrclear.ui.widget.guideview.GuideBuilder
import com.base.scanqrclear.ui.widget.guideview.LottieComponent
import com.base.scanqrclear.ui.wifi.WifiActivity import com.base.scanqrclear.ui.wifi.WifiActivity
import com.base.scanqrclear.utils.AppPreferences import com.base.scanqrclear.utils.AppPreferences
import com.base.scanqrclear.utils.BarUtils import com.base.scanqrclear.utils.BarUtils
...@@ -181,6 +184,10 @@ class CreateFragment : BaseFragment<FragmentCreateBinding>(FragmentCreateBinding ...@@ -181,6 +184,10 @@ class CreateFragment : BaseFragment<FragmentCreateBinding>(FragmentCreateBinding
override fun onResumeOneShoot() { override fun onResumeOneShoot() {
super.onResumeOneShoot() super.onResumeOneShoot()
adapter?.changeGuide() adapter?.changeGuide()
binding.root.post {
showGuideScan()
}
} }
override fun onResume() { override fun onResume() {
...@@ -189,6 +196,7 @@ class CreateFragment : BaseFragment<FragmentCreateBinding>(FragmentCreateBinding ...@@ -189,6 +196,7 @@ class CreateFragment : BaseFragment<FragmentCreateBinding>(FragmentCreateBinding
statusBarColor("#FFFFFFFF") statusBarColor("#FFFFFFFF")
statusBarDarkFont(true) statusBarDarkFont(true)
} }
setWeather() setWeather()
} }
...@@ -220,6 +228,34 @@ class CreateFragment : BaseFragment<FragmentCreateBinding>(FragmentCreateBinding ...@@ -220,6 +228,34 @@ class CreateFragment : BaseFragment<FragmentCreateBinding>(FragmentCreateBinding
// requireContext().showLogDialog(sb.toString()) // requireContext().showLogDialog(sb.toString())
// } // }
// } // }
}
private fun showGuideScan() {
val isGuideScan = AppPreferences.getInstance().getBoolean("isGuideScan", false)
if (isGuideScan) return
val activity = requireActivity() as MainActivity?
activity ?: return
val builder = GuideBuilder()
builder.setTargetView(binding.ivScan)
.setHighTargetGraphStyle(Component.CIRCLE)
.setAlpha(150)
.setHighTargetCorner(20)
.setHighTargetPadding(5)
.setExitAnimationId(android.R.anim.fade_out)
builder.setOnVisibilityChangedListener(object : GuideBuilder.OnVisibilityChangedListener {
override fun onShown() {
AppPreferences.getInstance().put("isGuideScan", true)
}
override fun onDismiss() {
startActivity(Intent(activity, ScanAc::class.java))
}
})
builder.addComponent(LottieComponent())
val guide = builder.createGuide()
guide.setShouldCheckLocInWindow(false)
guide.show(activity)
} }
} }
\ No newline at end of file
...@@ -28,6 +28,7 @@ import com.base.scanqrclear.luma.ActivityJumpHelps ...@@ -28,6 +28,7 @@ import com.base.scanqrclear.luma.ActivityJumpHelps
import com.base.scanqrclear.luma.HomeFragment import com.base.scanqrclear.luma.HomeFragment
import com.base.scanqrclear.ui.widget.AppExitDialog.showAppExitDialog import com.base.scanqrclear.ui.widget.AppExitDialog.showAppExitDialog
import com.base.scanqrclear.ui.widget.NotificationDialog.showNotificationTurnOn import com.base.scanqrclear.ui.widget.NotificationDialog.showNotificationTurnOn
import com.base.scanqrclear.utils.AppPreferences
import com.base.scanqrclear.utils.LogEx import com.base.scanqrclear.utils.LogEx
import com.base.scanqrclear.utils.PermissionUtils.areNotificationsEnabled import com.base.scanqrclear.utils.PermissionUtils.areNotificationsEnabled
import com.base.scanqrclear.utils.PermissionUtils.checkCameraPermission import com.base.scanqrclear.utils.PermissionUtils.checkCameraPermission
...@@ -83,7 +84,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl ...@@ -83,7 +84,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
// if (checkCameraPermission()) { // if (checkCameraPermission()) {
if (!bannerShowed.get()) { if (!bannerShowed.get()) {
bannerShowed.set(true) bannerShowed.set(true)
AdsMgr.showBanner(binding.flBanner, true) { val isGuideScan = AppPreferences.getInstance().getBoolean("isGuideScan", false)
AdsMgr.showBanner(binding.flBanner, isGuideScan) {
showNotificationDialog() showNotificationDialog()
} }
} else { } else {
......
package com.base.scanqrclear.ui.main package com.base.scanqrclear.ui.main
import androidx.activity.addCallback
import com.base.scanqrclear.ads.AdsMgr
import com.base.scanqrclear.ads.AdsShowCallBack
import com.base.scanqrclear.base.BaseActivity import com.base.scanqrclear.base.BaseActivity
import com.base.scanqrclear.bean.config.AdConfigBean
import com.base.scanqrclear.databinding.ActivityScanBinding import com.base.scanqrclear.databinding.ActivityScanBinding
import com.base.scanqrclear.qr.CameraUtils import com.base.scanqrclear.qr.CameraUtils
...@@ -15,6 +19,43 @@ class ScanAc : BaseActivity<ActivityScanBinding>(ActivityScanBinding::inflate) { ...@@ -15,6 +19,43 @@ class ScanAc : BaseActivity<ActivityScanBinding>(ActivityScanBinding::inflate) {
cameraUtils = CameraUtils(this) cameraUtils = CameraUtils(this)
} }
override fun onResumeOneShoot() {
super.onResumeOneShoot()
if (AdConfigBean.adsConfigBean.functionInShowAd) {
AdsMgr.showInsert(this, false, object : AdsShowCallBack() {
override fun close(where: Int) {
}
override fun failed(where: Int) {
}
override fun googleFailed(where: Int) {
}
})
}
}
override fun initListener() {
super.initListener()
onBackPressedDispatcher.addCallback {
if (AdConfigBean.adsConfigBean.functionBackShowAd) {
AdsMgr.showInsert(this@ScanAc, false, object : AdsShowCallBack() {
override fun close(where: Int) {
finishToMainTop()
}
override fun failed(where: Int) {
finishToMainTop()
}
override fun googleFailed(where: Int) {
finishToMainTop()
}
})
}
}
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
cameraUtils?.unBind() cameraUtils?.unBind()
......
...@@ -68,10 +68,11 @@ class ScanFragment : BaseFragment<FragmentScanBinding>(FragmentScanBinding::infl ...@@ -68,10 +68,11 @@ class ScanFragment : BaseFragment<FragmentScanBinding>(FragmentScanBinding::infl
override fun onResumeOneShoot() { override fun onResumeOneShoot() {
super.onResumeOneShoot() super.onResumeOneShoot()
val activity = requireActivity() as ScanAc?
if (requireContext().checkCameraPermission()) { if (requireContext().checkCameraPermission()) {
initCamera() initCamera()
} else { } else {
val activity = requireActivity() as ScanAc?
activity ?: return activity ?: return
activity.launcher.launch(arrayOf(Manifest.permission.CAMERA)) { activity.launcher.launch(arrayOf(Manifest.permission.CAMERA)) {
initCamera() initCamera()
......
package com.base.scanqrclear.ui.widget.guideview;
/**
* 遮罩系统运行异常的封装
* Created by binIoter
*/
class BuildException extends RuntimeException {
private static final long serialVersionUID = 6208777692136933357L;
private final String mDetailMessage;
public BuildException() {
mDetailMessage = "General error.";
}
public BuildException(String detailMessage) {
mDetailMessage = detailMessage;
}
@Override
public String getMessage() {
return "Build GuideFragment failed: " + mDetailMessage;
}
}
package com.base.scanqrclear.ui.widget.guideview;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.base.scanqrclear.utils.LogEx;
/**
* Created by binIoter
*/
class Common {
/**
* 设置Component
*/
static View componentToView(LayoutInflater inflater, Component c) {
View view = c.getView(inflater);
final MaskView.LayoutParams lp = new MaskView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
lp.offsetX = c.getXOffset();
lp.offsetY = c.getYOffset();
lp.targetAnchor = c.getAnchor();
lp.targetParentPosition = c.getFitPosition();
view.setLayoutParams(lp);
return view;
}
/**
* Rect在屏幕上去掉状态栏高度的绝对位置
*/
static Rect getViewAbsRect(View view, int parentX, int parentY) {
int[] loc = new int[2];
view.getLocationInWindow(loc);
LogEx.INSTANCE.logDebug("getViewAbsRect", "x=" + loc[0] + "y=" + loc[1], true);
Rect rect = new Rect();
rect.set(loc[0], loc[1], loc[0] + view.getMeasuredWidth(), loc[1] + view.getMeasuredHeight());
rect.offset(-parentX, -parentY);
return rect;
}
}
package com.base.scanqrclear.ui.widget.guideview;
import android.view.LayoutInflater;
import android.view.View;
/**
* * 遮罩系统中相对于目标区域而绘制一些图片或者文字等view需要实现的接口. <br>
* * <br>
* * {@link #getView(LayoutInflater)} <br>
* * {@link #getAnchor()} <br>
* * {@link #getFitPosition()} <br>
* * {@link #getXOffset()} <br>
* * {@link #getYOffset()}
* * <br>
* * 具体创建遮罩的说明请参加{@link GuideBuilder}
* *
*
* Created by binIoter
*/
public interface Component {
public final static int FIT_START = MaskView.LayoutParams.PARENT_START;
public final static int FIT_END = MaskView.LayoutParams.PARENT_END;
public final static int FIT_CENTER = MaskView.LayoutParams.PARENT_CENTER;
public final static int ANCHOR_LEFT = MaskView.LayoutParams.ANCHOR_LEFT;
public final static int ANCHOR_RIGHT = MaskView.LayoutParams.ANCHOR_RIGHT;
public final static int ANCHOR_BOTTOM = MaskView.LayoutParams.ANCHOR_BOTTOM;
public final static int ANCHOR_TOP = MaskView.LayoutParams.ANCHOR_TOP;
public final static int ANCHOR_OVER = MaskView.LayoutParams.ANCHOR_OVER;
/**
* 圆角矩形&矩形
*/
public final static int ROUNDRECT = 0;
/**
* 圆形
*/
public final static int CIRCLE = 1;
/**
* 需要显示的view
*
* @param inflater use to inflate xml resource file
* @return the component view
*/
View getView(LayoutInflater inflater);
/**
* 相对目标View的锚点
*
* @return could be {@link #ANCHOR_LEFT}, {@link #ANCHOR_RIGHT},
* {@link #ANCHOR_TOP}, {@link #ANCHOR_BOTTOM}, {@link #ANCHOR_OVER}
*/
int getAnchor();
/**
* 相对目标View的对齐
*
* @return could be {@link #FIT_START}, {@link #FIT_END},
* {@link #FIT_CENTER}
*/
int getFitPosition();
/**
* 相对目标View的X轴位移,在计算锚点和对齐之后。
*
* @return X轴偏移量, 单位 dp
*/
int getXOffset();
/**
* 相对目标View的Y轴位移,在计算锚点和对齐之后。
*
* @return Y轴偏移量,单位 dp
*/
int getYOffset();
}
package com.base.scanqrclear.ui.widget.guideview;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.View;
/**
* 遮罩系统创建时配置参数的封装 <br/>
* Created by binIoter
*/
class Configuration implements Parcelable {
/**
* 需要被找的View
*/
View mTargetView = null;
/**
* 高亮区域的padding
*/
int mPadding = 0;
/**
* 高亮区域的左侧padding
*/
int mPaddingLeft = 0;
/**
* 高亮区域的顶部padding
*/
int mPaddingTop = 0;
/**
* 高亮区域的右侧padding
*/
int mPaddingRight = 0;
/**
* 高亮区域的底部padding
*/
int mPaddingBottom = 0;
/**
* 是否可以透过蒙层点击,默认不可以
*/
boolean mOutsideTouchable = false;
/**
* 遮罩透明度
*/
int mAlpha = 255;
/**
* 遮罩覆盖区域控件Id
* <p/>
* 该控件的大小既该导航页面的大小
*/
int mFullingViewId = -1;
/**
* 目标控件Id
*/
int mTargetViewId = -1;
/**
* 高亮区域的圆角大小
*/
int mCorner = 0;
/**
* 高亮区域的图形样式,默认为矩形
*/
int mGraphStyle = Component.ROUNDRECT;
/**
* 遮罩背景颜色id
*/
int mFullingColorId = android.R.color.black;
/**
* 是否在点击的时候自动退出导航
*/
boolean mAutoDismiss = true;
/**
* 是否覆盖目标控件
*/
boolean mOverlayTarget = false;
boolean mShowCloseButton = false;
int mEnterAnimationId = -1;
int mExitAnimationId = -1;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mAlpha);
dest.writeInt(mFullingViewId);
dest.writeInt(mTargetViewId);
dest.writeInt(mFullingColorId);
dest.writeInt(mCorner);
dest.writeInt(mPadding);
dest.writeInt(mPaddingLeft);
dest.writeInt(mPaddingTop);
dest.writeInt(mPaddingRight);
dest.writeInt(mPaddingBottom);
dest.writeInt(mGraphStyle);
dest.writeByte((byte) (mAutoDismiss ? 1 : 0));
dest.writeByte((byte) (mOverlayTarget ? 1 : 0));
}
public static final Creator<Configuration> CREATOR = new Creator<Configuration>() {
@Override
public Configuration createFromParcel(Parcel source) {
Configuration conf = new Configuration();
conf.mAlpha = source.readInt();
conf.mFullingViewId = source.readInt();
conf.mTargetViewId = source.readInt();
conf.mFullingColorId = source.readInt();
conf.mCorner = source.readInt();
conf.mPadding = source.readInt();
conf.mPaddingLeft = source.readInt();
conf.mPaddingTop = source.readInt();
conf.mPaddingRight = source.readInt();
conf.mPaddingBottom = source.readInt();
conf.mGraphStyle = source.readInt();
conf.mAutoDismiss = source.readByte() == 1;
conf.mOverlayTarget = source.readByte() == 1;
return conf;
}
@Override
public Configuration[] newArray(int size) {
return new Configuration[size];
}
};
}
package com.base.scanqrclear.ui.widget.guideview;
import android.content.Context;
/**
* Created by binIoter
*/
public class DimenUtil {
/** sp转换成px */
public static int sp2px(Context context, float spValue) {
float fontScale = context.getApplicationContext().getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/** px转换成sp */
public static int px2sp(Context context, float pxValue) {
float fontScale = context.getApplicationContext().getResources().getDisplayMetrics().density;
return (int) (pxValue / fontScale + 0.5f);
}
/** dip转换成px */
public static int dp2px(Context context, float dipValue) {
float scale = context.getApplicationContext().getResources().getDisplayMetrics().scaledDensity;
return (int) (dipValue * scale + 0.5f);
}
/** px转换成dip */
public static int px2dp(Context context, float pxValue) {
float scale = context.getApplicationContext().getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / scale + 0.5f);
}
}
\ No newline at end of file
package com.base.scanqrclear.ui.widget.guideview;
import android.app.Activity;
import android.content.Context;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
/**
* 遮罩系统的封装 <br>
* * 外部需要调用{@link GuideBuilder}来创建该实例,实例创建后调用
* * {@link #show(Activity)} 控制显示; 调用 {@link #dismiss()}让遮罩系统消失。 <br>
* <p>
* Created by binIoter
*/
public class Guide implements View.OnKeyListener, View.OnTouchListener {
Guide() {
}
/**
* 滑动临界值
*/
private static final int SLIDE_THRESHOLD = 30;
private Configuration mConfiguration;
private MaskView mMaskView;
private Component[] mComponents;
// 根据locInwindow定位后,是否需要判断loc值非0
private boolean mShouldCheckLocInWindow = true;
private GuideBuilder.OnVisibilityChangedListener mOnVisibilityChangedListener;
private GuideBuilder.OnSlideListener mOnSlideListener;
void setConfiguration(Configuration configuration) {
mConfiguration = configuration;
}
void setComponents(Component[] components) {
mComponents = components;
}
void setCallback(GuideBuilder.OnVisibilityChangedListener listener) {
this.mOnVisibilityChangedListener = listener;
}
public void setOnSlideListener(GuideBuilder.OnSlideListener onSlideListener) {
this.mOnSlideListener = onSlideListener;
}
/**
* 显示遮罩
*
* @param activity 目标Activity
*/
public void show(Activity activity) {
show(activity, null);
}
/**
* 显示遮罩
*
* @param activity 目标Activity
* @param overlay 遮罩层view
*/
public void show(Activity activity, ViewGroup overlay) {
mMaskView = onCreateView(activity, overlay);
if (overlay == null) {
overlay = (ViewGroup) activity.getWindow().getDecorView();
}
if (mMaskView.getParent() == null && mConfiguration.mTargetView != null) {
overlay.addView(mMaskView);
if (mConfiguration.mEnterAnimationId != -1) {
Animation anim = AnimationUtils.loadAnimation(activity, mConfiguration.mEnterAnimationId);
assert anim != null;
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (mOnVisibilityChangedListener != null) {
mOnVisibilityChangedListener.onShown();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mMaskView.startAnimation(anim);
} else {
if (mOnVisibilityChangedListener != null) {
mOnVisibilityChangedListener.onShown();
}
}
}
}
public void clear() {
if (mMaskView == null) {
return;
}
final ViewGroup vp = (ViewGroup) mMaskView.getParent();
if (vp == null) {
return;
}
vp.removeView(mMaskView);
onDestroy();
}
/**
* 隐藏该遮罩并回收资源相关
*/
public void dismiss() {
if (mMaskView == null) {
return;
}
final ViewGroup vp = (ViewGroup) mMaskView.getParent();
if (vp == null) {
return;
}
if (mConfiguration.mExitAnimationId != -1) {
// mMaskView may leak if context is null
Context context = mMaskView.getContext();
assert context != null;
Animation anim = AnimationUtils.loadAnimation(context, mConfiguration.mExitAnimationId);
assert anim != null;
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
vp.removeView(mMaskView);
if (mOnVisibilityChangedListener != null) {
mOnVisibilityChangedListener.onDismiss();
}
onDestroy();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mMaskView.startAnimation(anim);
} else {
vp.removeView(mMaskView);
if (mOnVisibilityChangedListener != null) {
mOnVisibilityChangedListener.onDismiss();
}
onDestroy();
}
}
/**
* 根据locInwindow定位后,是否需要判断loc值非0
*/
public void setShouldCheckLocInWindow(boolean set) {
mShouldCheckLocInWindow = set;
}
private MaskView onCreateView(Activity activity, ViewGroup overlay) {
if (overlay == null) {
overlay = (ViewGroup) activity.getWindow().getDecorView();
}
MaskView maskView = new MaskView(activity);
maskView.setFullingColor(activity.getResources().getColor(mConfiguration.mFullingColorId));
maskView.setFullingAlpha(mConfiguration.mAlpha);
maskView.setHighTargetCorner(mConfiguration.mCorner);
maskView.setPadding(mConfiguration.mPadding);
maskView.setPaddingLeft(mConfiguration.mPaddingLeft);
maskView.setPaddingTop(mConfiguration.mPaddingTop);
maskView.setPaddingRight(mConfiguration.mPaddingRight);
maskView.setPaddingBottom(mConfiguration.mPaddingBottom);
maskView.setHighTargetGraphStyle(mConfiguration.mGraphStyle);
maskView.setOverlayTarget(mConfiguration.mOverlayTarget);
maskView.setOnKeyListener(this);
// For removing the height of status bar we need the root content view's
// location on screen
int parentX = 0;
int parentY = 0;
if (overlay != null) {
int[] loc = new int[2];
overlay.getLocationInWindow(loc);
parentX = loc[0];
parentY = loc[1];
}
if (mConfiguration.mTargetView != null) {
maskView.setTargetRect(Common.getViewAbsRect(mConfiguration.mTargetView, parentX, parentY));
} else {
// Gets the target view's abs rect
View target = activity.findViewById(mConfiguration.mTargetViewId);
if (target != null) {
maskView.setTargetRect(Common.getViewAbsRect(target, parentX, parentY));
}
}
if (mConfiguration.mOutsideTouchable) {
maskView.setClickable(false);
} else {
maskView.setOnTouchListener(this);
}
// Adds the components to the mask view.
for (Component c : mComponents) {
maskView.addView(Common.componentToView(activity.getLayoutInflater(), c));
}
return maskView;
}
private void onDestroy() {
mConfiguration = null;
mComponents = null;
mOnVisibilityChangedListener = null;
mOnSlideListener = null;
mMaskView.removeAllViews();
mMaskView = null;
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
if (mConfiguration != null && mConfiguration.mAutoDismiss) {
dismiss();
return true;
} else {
return false;
}
}
return false;
}
float startY = -1f;
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
startY = motionEvent.getY();
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
if (startY - motionEvent.getY() > DimenUtil.dp2px(view.getContext(), SLIDE_THRESHOLD)) {
if (mOnSlideListener != null) {
mOnSlideListener.onSlideListener(GuideBuilder.SlideState.UP);
}
} else if (motionEvent.getY() - startY > DimenUtil.dp2px(view.getContext(), SLIDE_THRESHOLD)) {
if (mOnSlideListener != null) {
mOnSlideListener.onSlideListener(GuideBuilder.SlideState.DOWN);
}
}
if (mConfiguration != null && mConfiguration.mAutoDismiss) {
dismiss();
}
}
return true;
}
}
package com.base.scanqrclear.ui.widget.guideview;
import android.annotation.SuppressLint;
import android.view.View;
import androidx.annotation.AnimatorRes;
import androidx.annotation.IdRes;
import androidx.annotation.IntRange;
import java.util.ArrayList;
import java.util.List;
/**
* <h1>遮罩系统构建器</h1>
* 本系统能够快速的为一个Activity里的任何一个View控件创建一个遮罩式的引导页。
* </p>
* <h3>工作原理</h3>
* 首先它需要一个目标View或者它的id,我们通过findViewById来得到这个View,计算它在屏幕上的区域targetRect,参见
* {@link #setTargetViewId(int)}与{@link #setTargetView(View)}通过这个区域,
* 开始绘制一个覆盖整个Activity的遮罩,可以定义蒙板的颜色{@link #setFullingColorId(int)}和透明度
* {@link #setAlpha(int)}。然而目标View的区域不会被绘制从而实现高亮的效果。
* </p>
* 接下来是在相对于这个targetRect的区域绘制一些图片或者文字。我们把这样一张图片或者文字抽象成一个Component接口
* {@link Component},设置文字或者图片等
* {@link Component#getView(android.view.LayoutInflater)}
* . 所有的图片文字都是相对于targetRect来定义的。可以设定额外的x,
* {@link Component#getXOffset()} ;y偏移量,
* {@link Component#getYOffset()}。
* </p>
* 可以对遮罩系统设置可见状态的发生变化时的监听回调
* {@link #setOnVisibilityChangedListener(OnVisibilityChangedListener)}
* </p>
* 可以对遮罩系统设置开始和结束时的动画效果 {@link #setEnterAnimationId(int)}
* {@link #setExitAnimationId(int)}
* </p>
* <p>
* Created by binIoter
**/
public class GuideBuilder {
public enum SlideState {
UP, DOWN;
}
private Configuration mConfiguration;
/**
* Builder被创建后,不允许在对它进行更改
*/
private boolean mBuilt;
private List<Component> mComponents = new ArrayList<Component>();
private OnVisibilityChangedListener mOnVisibilityChangedListener;
private OnSlideListener mOnSlideListener;
/**
* 构造函数
*/
public GuideBuilder() {
mConfiguration = new Configuration();
}
/**
* 设置蒙板透明度
*
* @param alpha [0-255] 0 表示完全透明,255表示不透明
* @return GuideBuilder
*/
public GuideBuilder setAlpha(@IntRange(from = 0, to = 255) int alpha) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
} else if (alpha < 0 || alpha > 255) {
alpha = 0;
}
mConfiguration.mAlpha = alpha;
return this;
}
/**
* 设置目标view
*/
public GuideBuilder setTargetView(View v) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
}
mConfiguration.mTargetView = v;
return this;
}
/**
* 设置目标View的id
*
* @param id 目标View的id
* @return GuideBuilder
*/
public GuideBuilder setTargetViewId(@IdRes int id) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
}
mConfiguration.mTargetViewId = id;
return this;
}
/**
* 设置高亮区域的圆角大小
*
* @return GuideBuilder
*/
public GuideBuilder setHighTargetCorner(int corner) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
} else if (corner < 0) {
mConfiguration.mCorner = 0;
}
mConfiguration.mCorner = corner;
return this;
}
/**
* 设置高亮区域的图形样式
*
* @return GuideBuilder
*/
public GuideBuilder setHighTargetGraphStyle(int style) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
}
mConfiguration.mGraphStyle = style;
return this;
}
/**
* 设置蒙板颜色的资源id
*
* @param id 资源id
* @return GuideBuilder
*/
@SuppressLint("ResourceType")
public GuideBuilder setFullingColorId(@IdRes int id) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
}
mConfiguration.mFullingColorId = id;
return this;
}
/**
* 是否在点击的时候自动退出蒙板
*
* @param b true if needed
* @return GuideBuilder
*/
public GuideBuilder setAutoDismiss(boolean b) {
if (mBuilt) {
throw new BuildException("Already created, rebuild a new one.");
}
mConfiguration.mAutoDismiss = b;
return this;
}
/**
* 是否覆盖目标
*
* @param b true 遮罩将会覆盖整个屏幕
* @return GuideBuilder
*/
public GuideBuilder setOverlayTarget(boolean b) {
if (mBuilt) {
throw new BuildException("Already created, rebuild a new one.");
}
mConfiguration.mOverlayTarget = b;
return this;
}
/**
* 设置进入动画
*
* @param id 进入动画的id
* @return GuideBuilder
*/
public GuideBuilder setEnterAnimationId(@AnimatorRes int id) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
}
mConfiguration.mEnterAnimationId = id;
return this;
}
/**
* 设置退出动画
*
* @param id 退出动画的id @AnimatorRes
* @return GuideBuilder
*/
public GuideBuilder setExitAnimationId(int id) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
}
mConfiguration.mExitAnimationId = id;
return this;
}
/**
* 添加一个控件
*
* @param component 被添加的控件
* @return GuideBuilder
*/
public GuideBuilder addComponent(Component component) {
if (mBuilt) {
throw new BuildException("Already created, rebuild a new one.");
}
mComponents.add(component);
return this;
}
/**
* 设置遮罩可见状态变化时的监听回调
*/
public GuideBuilder setOnVisibilityChangedListener(
OnVisibilityChangedListener onVisibilityChangedListener) {
if (mBuilt) {
throw new BuildException("Already created, rebuild a new one.");
}
mOnVisibilityChangedListener = onVisibilityChangedListener;
return this;
}
/**
* 设置手势滑动的监听回调
*/
public GuideBuilder setOnSlideListener(
OnSlideListener onSlideListener) {
if (mBuilt) {
throw new BuildException("Already created, rebuild a new one.");
}
mOnSlideListener = onSlideListener;
return this;
}
/**
* 设置遮罩系统是否可点击并处理点击事件
*
* @param touchable true 遮罩不可点击,处于不可点击状态 false 可点击,遮罩自己可以处理自身点击事件
*/
public GuideBuilder setOutsideTouchable(boolean touchable) {
mConfiguration.mOutsideTouchable = touchable;
return this;
}
/**
* 设置高亮区域的padding
*
* @return GuideBuilder
*/
public GuideBuilder setHighTargetPadding(int padding) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
} else if (padding < 0) {
mConfiguration.mPadding = 0;
}
mConfiguration.mPadding = padding;
return this;
}
/**
* 设置高亮区域的左侧padding
*
* @return GuideBuilder
*/
public GuideBuilder setHighTargetPaddingLeft(int padding) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
} else if (padding < 0) {
mConfiguration.mPaddingLeft = 0;
}
mConfiguration.mPaddingLeft = padding;
return this;
}
/**
* 设置高亮区域的顶部padding
*
* @return GuideBuilder
*/
public GuideBuilder setHighTargetPaddingTop(int padding) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
} else if (padding < 0) {
mConfiguration.mPaddingTop = 0;
}
mConfiguration.mPaddingTop = padding;
return this;
}
/**
* 设置高亮区域的右侧padding
*
* @return GuideBuilder
*/
public GuideBuilder setHighTargetPaddingRight(int padding) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
} else if (padding < 0) {
mConfiguration.mPaddingRight = 0;
}
mConfiguration.mPaddingRight = padding;
return this;
}
/**
* 设置高亮区域的底部padding
*
* @return GuideBuilder
*/
public GuideBuilder setHighTargetPaddingBottom(int padding) {
if (mBuilt) {
throw new BuildException("Already created. rebuild a new one.");
} else if (padding < 0) {
mConfiguration.mPaddingBottom = 0;
}
mConfiguration.mPaddingBottom = padding;
return this;
}
/**
* 创建Guide,非Fragment版本
*
* @return Guide
*/
public Guide createGuide() {
Guide guide = new Guide();
Component[] components = new Component[mComponents.size()];
guide.setComponents(mComponents.toArray(components));
guide.setConfiguration(mConfiguration);
guide.setCallback(mOnVisibilityChangedListener);
guide.setOnSlideListener(mOnSlideListener);
mComponents = null;
mConfiguration = null;
mOnVisibilityChangedListener = null;
mBuilt = true;
return guide;
}
/**
* 手势滑动监听
*/
public static interface OnSlideListener {
void onSlideListener(SlideState state);
}
/**
* 遮罩可见发生变化时的事件监听
*/
public static interface OnVisibilityChangedListener {
void onShown();
void onDismiss();
}
}
package com.base.scanqrclear.ui.widget.guideview;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.base.scanqrclear.R;
/**
* Created by binIoter on 16/6/17.
*/
public class LottieComponent implements Component {
@Override
public View getView(LayoutInflater inflater) {
LinearLayout ll = (LinearLayout) inflater.inflate(R.layout.layout_lottie_guide, null);
ll.setOnClickListener(view -> Toast.makeText(view.getContext(), "引导层被点击了", Toast.LENGTH_SHORT).show());
return ll;
}
@Override
public int getAnchor() {
return Component.ANCHOR_BOTTOM;
}
@Override
public int getFitPosition() {
return Component.FIT_CENTER;
}
@Override
public int getXOffset() {
return 0;
}
@Override
public int getYOffset() {
return -30;
}
}
package com.base.scanqrclear.ui.widget.guideview;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
/**
* Created by binIoter
*/
class MaskView extends ViewGroup {
/**
* 高亮区域
*/
private final RectF mTargetRect = new RectF();
/**
* 蒙层区域
*/
private final RectF mOverlayRect = new RectF();
/**
* 中间变量
*/
private final RectF mChildTmpRect = new RectF();
/**
* 蒙层背景画笔
*/
private final Paint mFullingPaint;
private int mPadding = 0;
private int mPaddingLeft = 0;
private int mPaddingTop = 0;
private int mPaddingRight = 0;
private int mPaddingBottom = 0;
/**
* 是否覆盖目标区域
*/
private boolean mOverlayTarget = false;
/**
* 圆角大小
*/
private int mCorner = 0;
/**
* 目标区域样式,默认为矩形
*/
private int mStyle = Component.ROUNDRECT;
/**
* 挖空画笔
*/
private Paint mEraser;
/**
* 橡皮擦Bitmap
*/
private Bitmap mEraserBitmap;
/**
* 橡皮擦Cavas
*/
private Canvas mEraserCanvas;
private boolean ignoreRepadding;
private int mInitHeight;
private int mChangedHeight = 0;
private boolean mFirstFlag = true;
public MaskView(Context context) {
this(context, null, 0);
}
public MaskView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MaskView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//自我绘制
setWillNotDraw(false);
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getRealMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
mOverlayRect.set(0, 0, width, height);
mEraserBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mEraserCanvas = new Canvas(mEraserBitmap);
mFullingPaint = new Paint();
mEraser = new Paint();
mEraser.setColor(0xFFFFFFFF);
//图形重叠时的处理方式,擦除效果
mEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//位图抗锯齿设置
mEraser.setFlags(Paint.ANTI_ALIAS_FLAG);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
try {
clearFocus();
mEraserCanvas.setBitmap(null);
mEraserBitmap = null;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int w = MeasureSpec.getSize(widthMeasureSpec);
final int h = MeasureSpec.getSize(heightMeasureSpec);
if (mFirstFlag) {
mInitHeight = h;
mFirstFlag = false;
}
if (mInitHeight > h) {
mChangedHeight = h - mInitHeight;
} else if (mInitHeight < h) {
mChangedHeight = h - mInitHeight;
} else {
mChangedHeight = 0;
}
setMeasuredDimension(w, h);
mOverlayRect.set(0, 0, w, h);
resetOutPath();
final int count = getChildCount();
View child;
for (int i = 0; i < count; i++) {
child = getChildAt(i);
if (child != null) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
final float density = getResources().getDisplayMetrics().density;
View child;
for (int i = 0; i < count; i++) {
child = getChildAt(i);
if (child == null) {
continue;
}
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp == null) {
continue;
}
switch (lp.targetAnchor) {
case LayoutParams.ANCHOR_LEFT://左
mChildTmpRect.right = mTargetRect.left;
mChildTmpRect.left = mChildTmpRect.right - child.getMeasuredWidth();
verticalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
break;
case LayoutParams.ANCHOR_TOP://上
mChildTmpRect.bottom = mTargetRect.top;
mChildTmpRect.top = mChildTmpRect.bottom - child.getMeasuredHeight();
horizontalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
break;
case LayoutParams.ANCHOR_RIGHT://右
mChildTmpRect.left = mTargetRect.right;
mChildTmpRect.right = mChildTmpRect.left + child.getMeasuredWidth();
verticalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
break;
case LayoutParams.ANCHOR_BOTTOM://下
mChildTmpRect.top = mTargetRect.bottom;
mChildTmpRect.bottom = mChildTmpRect.top + child.getMeasuredHeight();
horizontalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
break;
case LayoutParams.ANCHOR_OVER://中心
mChildTmpRect.left = ((int) mTargetRect.width() - child.getMeasuredWidth()) >> 1;
mChildTmpRect.top = ((int) mTargetRect.height() - child.getMeasuredHeight()) >> 1;
mChildTmpRect.right = ((int) mTargetRect.width() + child.getMeasuredWidth()) >> 1;
mChildTmpRect.bottom = ((int) mTargetRect.height() + child.getMeasuredHeight()) >> 1;
mChildTmpRect.offset(mTargetRect.left, mTargetRect.top);
break;
}
//额外的xy偏移
mChildTmpRect.offset((int) (density * lp.offsetX + 0.5f),
(int) (density * lp.offsetY + 0.5f));
child.layout((int) mChildTmpRect.left, (int) mChildTmpRect.top, (int) mChildTmpRect.right,
(int) mChildTmpRect.bottom);
}
}
private void horizontalChildPositionLayout(View child, RectF rect, int targetParentPosition) {
switch (targetParentPosition) {
case LayoutParams.PARENT_START:
rect.left = mTargetRect.left;
rect.right = rect.left + child.getMeasuredWidth();
break;
case LayoutParams.PARENT_CENTER:
rect.left = (mTargetRect.width() - child.getMeasuredWidth()) / 2;
rect.right = (mTargetRect.width() + child.getMeasuredWidth()) / 2;
rect.offset(mTargetRect.left, 0);
break;
case LayoutParams.PARENT_END:
rect.right = mTargetRect.right;
rect.left = rect.right - child.getMeasuredWidth();
break;
}
}
private void verticalChildPositionLayout(View child, RectF rect, int targetParentPosition) {
switch (targetParentPosition) {
case LayoutParams.PARENT_START:
rect.top = mTargetRect.top;
rect.bottom = rect.top + child.getMeasuredHeight();
break;
case LayoutParams.PARENT_CENTER:
rect.top = (mTargetRect.width() - child.getMeasuredHeight()) / 2;
rect.bottom = (mTargetRect.width() + child.getMeasuredHeight()) / 2;
rect.offset(0, mTargetRect.top);
break;
case LayoutParams.PARENT_END:
rect.bottom = mTargetRect.bottom;
rect.top = mTargetRect.bottom - child.getMeasuredHeight();
break;
}
}
private void resetOutPath() {
resetPadding();
}
/**
* 设置padding
*/
private void resetPadding() {
if (!ignoreRepadding) {
if (mPadding != 0 && mPaddingLeft == 0) {
mTargetRect.left -= mPadding;
}
if (mPadding != 0 && mPaddingTop == 0) {
mTargetRect.top -= mPadding;
}
if (mPadding != 0 && mPaddingRight == 0) {
mTargetRect.right += mPadding;
}
if (mPadding != 0 && mPaddingBottom == 0) {
mTargetRect.bottom += mPadding;
}
if (mPaddingLeft != 0) {
mTargetRect.left -= mPaddingLeft;
}
if (mPaddingTop != 0) {
mTargetRect.top -= mPaddingTop;
}
if (mPaddingRight != 0) {
mTargetRect.right += mPaddingRight;
}
if (mPaddingBottom != 0) {
mTargetRect.bottom += mPaddingBottom;
}
ignoreRepadding = true;
}
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
}
@Override
protected void dispatchDraw(Canvas canvas) {
final long drawingTime = getDrawingTime();
try {
View child;
for (int i = 0; i < getChildCount(); i++) {
child = getChildAt(i);
drawChild(canvas, child, drawingTime);
}
} catch (NullPointerException e) {
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mChangedHeight != 0) {
mTargetRect.offset(0, mChangedHeight);
mInitHeight = mInitHeight + mChangedHeight;
mChangedHeight = 0;
}
mEraserBitmap.eraseColor(Color.TRANSPARENT);
mEraserCanvas.drawColor(mFullingPaint.getColor());
if (!mOverlayTarget) {
switch (mStyle) {
case Component.ROUNDRECT:
mEraserCanvas.drawRoundRect(mTargetRect, mCorner, mCorner, mEraser);
break;
case Component.CIRCLE:
mEraserCanvas.drawCircle(mTargetRect.centerX(), mTargetRect.centerY(),
mTargetRect.width() / 2, mEraser);
break;
default:
mEraserCanvas.drawRoundRect(mTargetRect, mCorner, mCorner, mEraser);
break;
}
}
canvas.drawBitmap(mEraserBitmap, mOverlayRect.left, mOverlayRect.top, null);
}
public void setTargetRect(Rect rect) {
mTargetRect.set(rect);
}
public void setFullingAlpha(int alpha) {
mFullingPaint.setAlpha(alpha);
}
public void setFullingColor(int color) {
mFullingPaint.setColor(color);
}
public void setHighTargetCorner(int corner) {
this.mCorner = corner;
}
public void setHighTargetGraphStyle(int style) {
this.mStyle = style;
}
public void setOverlayTarget(boolean b) {
mOverlayTarget = b;
}
public void setPadding(int padding) {
this.mPadding = padding;
}
public void setPaddingLeft(int paddingLeft) {
this.mPaddingLeft = paddingLeft;
}
public void setPaddingTop(int paddingTop) {
this.mPaddingTop = paddingTop;
}
public void setPaddingRight(int paddingRight) {
this.mPaddingRight = paddingRight;
}
public void setPaddingBottom(int paddingBottom) {
this.mPaddingBottom = paddingBottom;
}
static class LayoutParams extends ViewGroup.LayoutParams {
public static final int ANCHOR_LEFT = 0x01;
public static final int ANCHOR_TOP = 0x02;
public static final int ANCHOR_RIGHT = 0x03;
public static final int ANCHOR_BOTTOM = 0x04;
public static final int ANCHOR_OVER = 0x05;
public static final int PARENT_START = 0x10;
public static final int PARENT_CENTER = 0x20;
public static final int PARENT_END = 0x30;
public int targetAnchor = ANCHOR_BOTTOM;
public int targetParentPosition = PARENT_CENTER;
public int offsetX = 0;
public int offsetY = 0;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
}
}
...@@ -47,18 +47,32 @@ ...@@ -47,18 +47,32 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_weather" /> app:layout_constraintTop_toTopOf="@id/tv_weather" />
<TextView <LinearLayout
android:id="@+id/tv_logo" android:id="@+id/tv_logo"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:drawablePadding="13dp" android:orientation="vertical"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="19sp"
app:drawableTopCompat="@mipmap/codescan"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_zodiac" /> app:layout_constraintTop_toBottomOf="@id/tv_zodiac"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/ivScan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@mipmap/codescan"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="13dp"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="19sp" />
</LinearLayout>
<!-- <ImageView--> <!-- <ImageView-->
<!-- android:id="@+id/ivVip"--> <!-- android:id="@+id/ivVip"-->
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.airbnb.lottie.LottieAnimationView
android:layout_width="240dp"
android:layout_height="240dp"
android:layout_gravity="center_horizontal"
android:scaleType="centerCrop"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="@raw/guide_finger" />
</LinearLayout>
\ No newline at end of file
{"nm":"tap","ddd":0,"h":500,"w":500,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":5000,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-27,-92,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0,0,100],"t":61},{"s":[263,263,100],"t":88}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[246,197,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[100],"t":61},{"s":[0],"t":86}],"ix":11,"x":"var $bm_rt;\n$bm_rt = transform.opacity;"}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[55.734,55.734],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[5],"t":61},{"s":[0],"t":92}],"ix":5},"c":{"a":0,"k":[1,0.7451,0.7451],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-28.133,-94.133],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"hand","sr":1,"st":0,"op":5000,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10,14.5,0],"ix":1},"s":{"a":0,"k":[586,586,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[264.319,272.606,0],"ix":2},"r":{"a":0,"k":-32,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[-0.988,2.4],[0.722,0.509],[0.006,0.278],[0.618,0.385],[0.272,0.057],[0.027,0.017],[-0.003,0.108],[0.662,0.412],[0.279,0.07],[0.023,0.015],[-0.084,0.136],[0,0],[0.834,0.519],[0.692,-1.112],[0,0],[0.414,0.257],[0.007,0.36],[0,0],[0.509,0.317],[0.022,-1.817],[0,0],[-0.089,-0.056],[-2.181,-1.312],[-0.045,0.063],[0,0],[-0.045,0.02]],"o":[[1.029,-2.5],[-0.228,-0.161],[-0.028,-1.168],[-0.443,-0.276],[-0.035,-0.006],[-0.088,-0.054],[0.038,-1.29],[-0.385,-0.24],[-0.03,-0.007],[-0.127,-0.079],[0,0],[0.692,-1.112],[-0.835,-0.52],[0,0],[-0.313,0.503],[-0.252,-0.157],[0,0],[0.01,-0.804],[-1.15,-0.716],[0,0],[-0.007,0.104],[0,0],[2.393,1.439],[0,0],[0.028,-0.04],[4.267,-1.959]],"v":[[9.386,4.737],[8.322,0.373],[7.943,-0.322],[6.705,-2.547],[5.532,-3.008],[5.438,-3.045],[5.298,-3.308],[4.041,-5.742],[2.981,-6.184],[2.901,-6.218],[2.811,-6.606],[5.84,-11.472],[5.216,-14.176],[2.514,-13.543],[-2.815,-4.983],[-4.147,-4.683],[-4.591,-5.474],[-4.628,-7.214],[-5.491,-8.897],[-8.559,-7.262],[-9.755,8.699],[-9.613,8.943],[-5.293,12.327],[-0.398,14.39],[2.063,10.93],[2.172,10.842]]}],"t":50},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[-0.988,2.4],[0.722,0.509],[0.006,0.278],[0.618,0.385],[0.272,0.057],[0.027,0.017],[-0.003,0.108],[0.662,0.412],[0.279,0.07],[0.023,0.015],[-0.084,0.136],[0,0],[0.834,0.519],[0.692,-1.112],[0,0],[0.414,0.257],[0.007,0.36],[0,0],[0.509,0.317],[0.022,-1.817],[0,0],[-0.089,-0.056],[-2.181,-1.312],[-0.045,0.063],[0,0],[-0.045,0.02]],"o":[[1.029,-2.5],[-0.228,-0.161],[-0.028,-1.168],[-0.443,-0.276],[-0.035,-0.006],[-0.088,-0.054],[0.038,-1.29],[-0.385,-0.24],[-0.03,-0.007],[-0.127,-0.079],[0,0],[0.692,-1.112],[-0.835,-0.52],[0,0],[-0.313,0.503],[-0.252,-0.157],[0,0],[0.01,-0.804],[-1.15,-0.716],[0,0],[-0.007,0.104],[0,0],[2.393,1.439],[0,0],[0.028,-0.04],[4.267,-1.959]],"v":[[9.386,4.737],[8.322,0.373],[7.943,-0.322],[6.705,-2.547],[5.532,-3.008],[5.438,-3.045],[5.298,-3.308],[4.041,-5.742],[2.981,-6.184],[2.901,-6.218],[2.811,-6.606],[4.646,-9.424],[4.022,-12.128],[1.32,-11.495],[-2.815,-4.983],[-4.147,-4.683],[-4.591,-5.474],[-4.628,-7.214],[-5.491,-8.897],[-8.559,-7.262],[-9.755,8.699],[-9.613,8.943],[-4.677,11.241],[-0.398,14.39],[2.063,10.93],[2.172,10.842]]}],"t":61},{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":1},"s":[{"c":true,"i":[[-0.988,2.4],[0.722,0.509],[0.006,0.278],[0.618,0.385],[0.272,0.057],[0.027,0.017],[-0.003,0.108],[0.662,0.412],[0.279,0.07],[0.023,0.015],[-0.084,0.136],[0,0],[0.834,0.519],[0.692,-1.112],[0,0],[0.414,0.257],[0.007,0.36],[0,0],[0.509,0.317],[0.022,-1.817],[0,0],[-0.089,-0.056],[-2.181,-1.312],[-0.045,0.063],[0,0],[-0.045,0.02]],"o":[[1.029,-2.5],[-0.228,-0.161],[-0.028,-1.168],[-0.443,-0.276],[-0.035,-0.006],[-0.088,-0.054],[0.038,-1.29],[-0.385,-0.24],[-0.03,-0.007],[-0.127,-0.079],[0,0],[0.692,-1.112],[-0.835,-0.52],[0,0],[-0.313,0.503],[-0.252,-0.157],[0,0],[0.01,-0.804],[-1.15,-0.716],[0,0],[-0.007,0.104],[0,0],[2.393,1.439],[0,0],[0.028,-0.04],[4.267,-1.959]],"v":[[9.386,4.737],[8.322,0.373],[7.943,-0.322],[6.705,-2.547],[5.532,-3.008],[5.438,-3.045],[5.298,-3.308],[4.041,-5.742],[2.981,-6.184],[2.901,-6.218],[2.811,-6.606],[5.84,-11.472],[5.216,-14.176],[2.514,-13.543],[-2.815,-4.983],[-4.147,-4.683],[-4.591,-5.474],[-4.628,-7.214],[-5.491,-8.897],[-8.559,-7.262],[-9.755,8.699],[-9.613,8.943],[-5.267,12.306],[-0.398,14.39],[2.063,10.93],[2.172,10.842]]}],"t":72},{"s":[{"c":true,"i":[[-0.988,2.4],[0.722,0.509],[0.006,0.278],[0.618,0.385],[0.272,0.057],[0.027,0.017],[-0.003,0.108],[0.662,0.412],[0.279,0.07],[0.023,0.015],[-0.084,0.136],[0,0],[0.834,0.519],[0.692,-1.112],[0,0],[0.414,0.257],[0.007,0.36],[0,0],[0.509,0.317],[0.022,-1.817],[0,0],[-0.089,-0.056],[-3.329,-1.925],[-0.044,0.062],[0,0],[-0.045,0.02]],"o":[[1.029,-2.5],[-0.228,-0.161],[-0.028,-1.168],[-0.443,-0.276],[-0.035,-0.006],[-0.088,-0.054],[0.038,-1.29],[-0.385,-0.24],[-0.03,-0.007],[-0.127,-0.079],[0,0],[0.692,-1.112],[-0.835,-0.52],[0,0],[-0.313,0.503],[-0.252,-0.157],[0,0],[0.01,-0.804],[-1.15,-0.716],[0,0],[-0.007,0.104],[0,0],[3.323,1.921],[0,0],[0.028,-0.04],[4.267,-1.959]],"v":[[9.386,4.737],[8.322,0.373],[7.943,-0.322],[6.705,-2.547],[5.532,-3.008],[5.438,-3.045],[5.298,-3.308],[4.041,-5.742],[2.981,-6.184],[2.901,-6.218],[2.811,-6.606],[5.84,-11.472],[5.216,-14.176],[2.514,-13.543],[-2.815,-4.983],[-4.147,-4.683],[-4.591,-5.474],[-4.628,-7.214],[-5.491,-8.897],[-8.559,-7.262],[-9.755,8.699],[-9.613,8.943],[-5.305,12.33],[-0.398,14.39],[2.063,10.93],[2.172,10.842]]}],"t":85}],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[1,1,1],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[9.755,14.498],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2}],"v":"5.6.3","fr":50,"op":109,"ip":50,"assets":[]}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment