转载请标明出处:一片枫叶的专栏
上一篇文章中讲解了我最近写的一个快速集成二维码扫描库,其核心的实现扫描的功能,是通过调用ZXing库实现的。由于在实现二维码扫描功能的时候发现集成二维码扫描功能并不是特别方便,于是有了将其制作成标准库的想法,这个二维码库能够快速,方便的集成二维码扫描功能,项目地址是在:android-zxingLibrary**,在项目开源后有不少同学提出了许多不错的意见,目前也在不断的迭代中,自己也学到了很多。
本文我们将讲解一个简单,强大的广告活动弹窗控件。不少App在打开的时候需要弹出一个广告活动弹窗,点击广告活动弹窗中的图片就会跳转到一个H5页面,加载显示具体的活动内容等,为了方便大家的操作,我将其做成了一个标准控件:android-adDialog。需要说明的是,虽然其名称为android-adDialog,并且表现形式也和Dialog类似,但是这里并不是通过Dialog实现的,而是自定义的View。
本项目的github地址:android-adDialog,欢迎star和follow。
在介绍具体的使用说明之前,我们先看一下简单的实现效果:
))
/** * 设置弹窗背景是否透明 */
.setAnimBackViewTransparent(true)
/** * 设置弹窗关闭图标是否可见 */
.setDialogCloseable(false)
/** * 设置弹窗弹性滑动弹性值 */
.setBounciness(15)
/** * 设置弹窗弹性滑动速度值 */
.setSpeed(5)
/** * 设定弹窗点击事件回调 */
.setOnImageClickListener(new AdManager.OnImageClickListener() {})
/** * 设定关闭按钮点击事件回调 */
.setOnCliseClickListener(new OnClickListener() {})
/** * 开始执行弹窗的显示操作,可传值为0-360,0表示从右开始弹出,逆时针方向,也可以传入自定义的方向值 */
.showAdDialog(AdConstant.ANIM_UP_TO_DOWN)
使用方式:
- 在module的build.gradle中执行compile操作
compile 'cn.yipianfengye.android:ad-library:1.0'
- 在代码中初始化数据
/** * 初始化数据 */
private void initData() {
advList = new ArrayList<>();
AdInfo adInfo = new AdInfo();
adInfo.setActivityImg("https://raw.githubusercontent.com/yipianfengye/android-adDialog/master/images/testImage1.png");
advList.add(adInfo);
adInfo = new AdInfo();
adInfo.setActivityImg("https://raw.githubusercontent.com/yipianfengye/android-adDialog/master/images/testImage2.png");
advList.add(adInfo);
}
这里只要是初始化图片的UI地址信息,方便我们的后续下载操作。
- 执行弹窗的初始化与现实操作
/** * 创建广告活动管理对象 */
AdManager adManager = new AdManager(MainActivity.this, advList);
adManager.setOverScreen(true)
.setPageTransformer(new DepthPageTransformer());
/** * 执行弹窗的显示操作 */
adManager.showAdDialog(AdConstant.ANIM_DOWN_TO_UP);
怎么样是不是很简单?下面我们可以来看一下具体API。
具体的API说明:
- (1)自定义的弹窗弹出方向API
在执行AdManager的showAdDialog方法时,需要传递一个int型的animType参数,我们默认定义了八个该类型的参数,默认如下:
// ####################### 弹出动画效果 ###########################
/** * 广告活动弹窗动画-从上至下 */
public static final int ANIM_UP_TO_DOWN = -11;
/** * 广告活动弹窗动画-从下至上 */
public static final int ANIM_DOWN_TO_UP = -12;
/** * 广告活动弹窗动画-从左至右 */
public static final int ANIM_LEFT_TO_RIGHT = -13;
/** * 广告活动弹窗动画-从右至左 */
public static final int ANIM_RIGHT_TO_LEFT = -14;
/** * 广告活动弹窗动画-从左上弹出 */
public static final int ANIM_UPLEFT_TO_CENTER = -15;
/** * 广告活动弹窗动画-从右上弹出 */
public static final int ANIM_UPRIGHT_TO_CENTER = -16;
/** * 广告活动弹窗动画-从左下弹出 */
public static final int ANIM_DOWNLEFT_TO_CENTER = -17;
/** * 广告活动弹窗动画-从右下弹出 */
public static final int ANIM_DOWNRIGHT_TO_CENTER = -18;
好吧,如果你觉得还不够好,我想让弹窗从右上侧30度角的弹出可以么?这也是支持的,只需要你传递的int型的animType的时候传递30就好了,如下:
/** * 执行弹窗的显示操作(参数的范围:0-360,0表示从右侧弹出,逆时针旋转) */
adManager.showAdDialog(30);
那么我们看一下执行效果呢:
, Toast.LENGTH_SHORT).show(); } }) .setPadding(100) .setWidthPerHeight(0.5f) .showAdDialog(AdConstant.ANIM_UP_TO_DOWN); } });
然后我们看一下执行效果:
, Toast.LENGTH_SHORT).show(); } }) .setBackViewColor(Color.parseColor("#AA333333")) .setDialogCloseable(false) .showAdDialog(AdConstant.ANIM_UP_TO_DOWN); } });
然后我们来看一下具体的实现效果:
, Toast.LENGTH_SHORT).show(); } }) .setBounciness(20) .setSpeed(4) .showAdDialog(AdConstant.ANIM_UP_TO_DOWN); } });
然后我们看一下动画效果:
, Toast.LENGTH_SHORT).show();
}
})
.setPageTransformer(new RotateDownPageTransformer())
.showAdDialog(AdConstant.ANIM_UP_TO_DOWN);
}
});
然后我们看一下弹窗的滑动动画:
, Toast.LENGTH_SHORT).show(); } }) .setOnCloseClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "您点击了关闭按钮...", Toast.LENGTH_SHORT).show(); } }) .showAdDialog(AdConstant.ANIM_UP_TO_DOWN); } });
好吧,以上就是广告活动弹窗的API,除了以上还可以添加其他的一些API,欢迎提出。
自定义广告活动弹窗的实现过程:
- 自定义广告弹窗对象
主要用于管理自定义View,ViewPager等对象;这里我们可以看一下弹窗展示方法的实现:
/** * 开始执行显示广告弹窗的操作 * @param animType */
public void showAdDialog(final int animType) {
contentView = LayoutInflater.from(context).inflate(R.layout.ad_dialog_content_layout, null);
adRootContent = (RelativeLayout) contentView.findViewById(R.id.ad_root_content);
viewPager = (ViewPager) contentView.findViewById(R.id.viewPager);
mIndicator = (FlycoPageIndicaor) contentView.findViewById(R.id.indicator);
adAdapter = new AdAdapter();
viewPager.setAdapter(adAdapter);
if (pageTransformer != null) {
viewPager.setPageTransformer(true, pageTransformer);
}
mIndicator.setViewPager(viewPager);
isShowIndicator();
animDialogUtils = AnimDialogUtils.getInstance(context)
.setAnimBackViewTransparent(isAnimBackViewTransparent)
.setDialogCloseable(isDialogCloseable)
.setDialogBackViewColor(backViewColor)
.setOnCloseClickListener(onCloseClickListener)
.setOverScreen(isOverScreen)
.initView(contentView);
setRootContainerHeight();
// 延迟1s展示,为了避免ImageLoader还为加载完缓存图片时就展示了弹窗的情况
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
animDialogUtils.show(animType, bounciness, speed);
}
}, 1000);
}
- 自定义弹窗对象
在广告活动弹窗对象中我们调用了:
AnimDialogUtils.getInstance(context)
.setAnimBackViewTransparent(isAnimBackViewTransparent)
.setDialogCloseable(isDialogCloseable)
.setDialogBackViewColor(backViewColor)
.setOnCloseClickListener(onCloseClickListener)
.setOverScreen(isOverScreen)
.initView(contentView);
而这里的AnimDialogUtils主要用于实现类似Dialog的效果,这里我们看一下自定义弹窗展示方法的具体实现:
/** * 初始化弹窗中的界面,添加传入的customView界面,并监听关闭按钮点击事件 * * @param customView * @return */
public AnimDialogUtils initView(final View customView) {
if (isOverScreen) {
androidContentView = (ViewGroup) context.getWindow().getDecorView();
} else {
androidContentView = (ViewGroup) context.getWindow().findViewById(Window.ID_ANDROID_CONTENT);
}
rootView = LayoutInflater.from(context).inflate(R.layout.anim_dialog_layout, null);
rootView.setTag(ANIM_DIALOG_TAG);
animBackView = (RelativeLayout) rootView.findViewById(R.id.anim_back_view);
animContainer = (RelativeLayout) rootView.findViewById(R.id.anim_container);
animContainer.setVisibility(View.INVISIBLE);
flContentContainer = (FrameLayout) rootView.findViewById(R.id.fl_content_container);
ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
flContentContainer.addView(customView, contentParams);
ivClose = (ImageView) rootView.findViewById(R.id.iv_close);
return this;
}
/** * 开始执行弹窗的展示动画 * @param animType */
public void show(int animType, double bounciness, double speed) {
// 判断是否设置背景透明
if (isAnimBackViewTransparent) {
backViewColor = Color.TRANSPARENT;
}
// 判断背景颜色
animBackView.setBackgroundColor(backViewColor);
// 判断弹窗是否可关闭
if (isDialogCloseable) {
ivClose.setVisibility(View.VISIBLE);
ivClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (onCloseClickListener != null) {
onCloseClickListener.onClick(view);
}
dismiss(AdConstant.ANIM_STOP_TRANSPARENT);
}
});
} else {
ivClose.setVisibility(View.GONE);
}
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
androidContentView.addView(rootView, params);
AnimSpring.getInstance().startAnim(animType, animContainer, bounciness, speed);
isShowing = true;
}
- 自定义弹性滑动工具类
在上面的弹窗展示方法中我们最终调用了:
AnimSpring.getInstance().startAnim(animType, animContainer, bounciness, speed);
在实现弹窗的弹性滑动过程中使用了Facebook的rebound框架,自定义了一个弹性滑动工具类,在其中初始化rebound的SpringSystem对象,并实现了弹窗的各个角度的弹性滑动效果:
/** * 开始动画-定义动画开始角度 * @param animType * @param animContainer */
public void startCircleAnim(final int animType, final RelativeLayout animContainer) {
double radius = Math.sqrt(DisplayUtil.screenhightPx * DisplayUtil.screenhightPx + DisplayUtil.screenWidthPx * DisplayUtil.screenWidthPx);
double heightY = - Math.sin(Math.toRadians(animType)) * radius;
double widthX = Math.cos(Math.toRadians(animType)) * radius;
Spring tranSpring = springSystem.createSpring();
Spring tranSpring1 = springSystem.createSpring();
tranSpring.addListener(new SimpleSpringListener() {
@Override
public void onSpringActivate(Spring spring) {
animContainer.setVisibility(View.VISIBLE);
}
@Override
public void onSpringUpdate(Spring spring) {
animContainer.setTranslationX((float) spring.getCurrentValue());
}
});
tranSpring1.addListener(new SimpleSpringListener() {
@Override
public void onSpringActivate(Spring spring) {
animContainer.setVisibility(View.VISIBLE);
}
@Override
public void onSpringUpdate(Spring spring) {
animContainer.setTranslationY((float) spring.getCurrentValue());
}
});
tranSpring.setSpringConfig(springConfig);
tranSpring1.setSpringConfig(springConfig);
tranSpring.setCurrentValue(widthX);
tranSpring.setEndValue(0);
tranSpring1.setCurrentValue(heightY);
tranSpring1.setEndValue(0);
}
这样就实现了对弹窗的初始化,展示,动画效果的实现等操作。
- 使用Fresco实现图片的下载操作
在我们的ViewPager初始化图片的时候是通过Fresco类库实现对图片URL的下载操作的:
@Override
public Object instantiateItem(ViewGroup container, int position) {
/** * 初始化ViewPager Item内容 */
AdInfo advInfo = advInfoListList.get(position);
View rootView = context.getLayoutInflater().inflate(R.layout.viewpager_item, null);
final ViewGroup errorView = (ViewGroup) rootView.findViewById(R.id.error_view);
final ViewGroup loadingView = (ViewGroup) rootView.findViewById(R.id.loading_view);
final SimpleDraweeView simpleDraweeView = (SimpleDraweeView) rootView.findViewById(R.id.simpleDraweeView);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
container.addView(rootView, params);
simpleDraweeView.setTag(advInfo);
simpleDraweeView.setOnClickListener(imageOnClickListener);
/** * 监听图片下载动作 */
ControllerListener controllerListener = new BaseControllerListener<ImageInfo>() {
@Override
public void onFinalImageSet(
String id,
@Nullable ImageInfo imageInfo,
@Nullable Animatable anim) {
if (imageInfo == null) {
return;
}
errorView.setVisibility(View.GONE);
loadingView.setVisibility(View.GONE);
simpleDraweeView.setVisibility(View.VISIBLE);
}
@Override
public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
Log.i("##########", "onIntermediateImageSet()");
}
@Override
public void onFailure(String id, Throwable throwable) {
errorView.setVisibility(View.VISIBLE);
loadingView.setVisibility(View.GONE);
simpleDraweeView.setVisibility(View.GONE);
}
};
Uri uri = Uri.parse(advInfo.getActivityImg());
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setControllerListener(controllerListener)
.setUri(uri)
.build();
simpleDraweeView.setController(controller);
return rootView;
}
当然更具体的关于广告活动弹窗控件的实现可以下载源码参考。
总结:
以上就是我实现的这个自定义广告活动弹窗控件。其还可以添加一些其他的API,欢迎提出,对于源码有兴趣的同学可以到github上看一下具体实现。项目地址:android-adDialog
另外对github项目,开源项目解析感兴趣的同学可以参考我的:
Github项目解析(一)–>上传Android项目至github
Github项目解析(二)–>将Android项目发布至JCenter代码库
Github项目解析(三)–>Android内存泄露监测之leakcanary
Github项目解析(四)–>动态更改TextView的字体大小
Github项目解析(五)–>Android日志框架
Github项目解析(六)–>自定义实现ButterKnife框架
Github项目解析(七)–>防止按钮重复点击
Github项目解析(八)–>Activity启动过程中获取组件宽高的五种方式
Github项目解析(九)–>实现Activity跳转动画的五种方式
Github项目解析(十)–>几行代码快速集成二维码扫描库