qq空间背景图片代码大全(qq空间背景图片代码怎么弄)

前言

qq空间背景图片代码大全(qq空间背景图片代码怎么弄)

弹幕除了直播还能用来做什么?如果你看过QQ空,你一定知道QQ空里的图片预览用的是弹幕。今天出于学习的目的,我们来实现一个QQ空之间的图片预览对话框。如果你上周碰巧看了我的博客,你一定知道我上周写了《如何实现弹幕https://www.jianshu.com/p/2b1f4da434f3.》

如果你注意细节,找到这个库还是很有意思的:

弹幕众多的手势(很大一部分来自PhotoView)随着滑动高度变化的背景透明度多种动画由于之前我已经讲过如何实现弹幕,所以在本文中,不会涉及到如何实现弹幕,只会直接引用

弹幕库:https://github.com/mCyp/Muti-Barrage

目录

一、整体把握

我们可以用什么来预览QQ空之间的图片?首先,我们的基础必须是对话;;其次,可以使用ViewPager切换图片。同样,你也可以使用ViewPager2,它可以支持垂直画面切换和更好的动画过渡。但是,ViewPager2属于androidx。如果使用ViewPager2,那么整个库需要迁移到androidx然后,我们可以使用PhotoView进行手势处理和图片,多弹幕;之前写的可以用来弹幕。最后你可能会问,这么多第三方库,我们还能大显身手吗?剩下的工作比较轻松,主要负责处理触摸事件和动画。好了,现在整个结构清晰了,View pager+PhotoView+多弹幕视图和手势处理+动画可以在QQ空之间形成一个简单的图片预览。

“1.类图”上面,我们已经知道需要用什么技术来实现它。现在,让我们来看看主要的UML类图,以便于我们实际解释下面的代码:

聪明的你可能发现了,这不就是代理模式吗?精确地

二、代码实战

既然已经上了UML类图,那就按照UML类图的顺序来说吧。

「1.IPhotoPager】

public interfaceiphopager { void show();void dissolve();voidsetConfig(config config);/* config */class config { List & lt;字符串& gt路径;//图片路径列表< Bitmap & gt位图;//BitmapbooleancanDelete = true;//普通主题使用booleanisShowAnimation = false//是否显示动画booleanisShowBarrage = true//是否在animationType中显示弹幕;//动画类型intstartPosition = 0;//图片开始位置DeleteListenerdeleteListener//删除侦听器列表拦河坝;//弹幕数据}}IPhotoPager定义了一些基本的约束和一些我们需要用到的数据类型。

「2.基地传呼机

publicacstractclassbasepagerendedsdialogimplementsviewpager。OnPageChangeListener,IPhotoPager { protectedContextmContext;//allbaseinfoprivateIPhotoPager。ConfigmConfig//basicinfoprotectedintentcurposition;protectedbooleanisCanDeleteprotectedbooleanisShowAnimation;protectedintanimationTypeprotecteddeletelestenerdeletelistener;protectedbooleanisShowBarrages;protectedList & lt位图& gt位图;protectedList & ltBarrageData & gt拦河坝;public base pager(@ NonNullContextcontext){ this(context,r . style . dialog);} public base pager(@ NonNullContextcontext,intthemeResId){super(context,themeResId);mContext =上下文;} @ OverrideprotectedvoidonCreate(BundlesavedInstanceState){ super . oncreate(savedInstanceState);window window = getWindow();如果(窗口!= null){ window . setdimamount(1f);}}//…省略view pager @ OverridePublicVoidsetConfig(config config){ this . mconfig = config;init params();}/* init parameter */privatevoidinitParams(){ this . iscan delete = mconfig . can delete;this . isshowmanimation = mconfig . isshowmanimation;this . animation type = mconfig . animation type;this . cur position = mconfig . start position;//initbitmapstthis . bitmaps = new ArrayList & lt;& gt();this . bitmaps . addall(mconfig . bitmaps);this . delete listener = mconfig . delete listener;this . barrages = mconfig . barrages;this . isshowbarrages = mconfig . isshowbarrage;} @ Overridepublicvoidshow(){ if(bitmaps = = null | | bitmaps . size()= = 0){ thrownewRuntimeException(& # 34;位图扫描& # 39;tbenull & # 34);} super . show();//setingrectmustbeafterdialog . showing(),otherwisedialogwillshowininitialsize。rect rect = new rect();((Activity)mContext)。getWindow()。getDecorView()。getWindowVisibleDisplayFrame(rect);//setpositionandsizewindow = getWindow();窗口管理器。LayoutParamslp = window . get attributes();lp.gravity =重力。底部;lp.width=WindowManager。LayoutParams . MATCH _ PARENTLP . height = rect . height();window . set attributes(LP);if(isshowmanimation){ if(ANIMATION type = = ANIMATION _ SCALE _ ALPHA){ window . setwindow animations(r . style . photopagerscale);} else if(ANIMATION type = = ANIMATION _ TRANSLATION){ window . setwindowanimations(r . style . photopagertranslation);} else {//defaultanimationstrationwindow . setwindow animations(r . style . photopageralpha);} } } } base pager的内容也相当简单。ViewPager的监听器是实现的,虽然它不做任何事情。其次,获得的配置初始化基本数据。

「3.QQ传呼机】

QQPager的代码将近400行左右,还是按照流程拆分讲解。

3.1数据初始化

数据初始化主要分为初始化视图页面和多页面视图,这是一个简单的初始化过程。这里,只介绍我们的数据:

public classqqpagerextendsbasepager { privatestaticfinalStringTAG = & # 34;QQ寻呼机& # 34;;privatestaticfinallintscroll _ THRESHOlD = 100;//滑动阈值privatestaticfinallintmsg _ UP = 0;privateImageViewmBarrage//弹幕privateMyViewPagermPhotoPager的开关;//简单处理的viewpagerprivatetextviewsposition;//位置信息privatepogetageradapteradapter;//ViewPager的项是photoviewprivatebarrageviewbarrageview;privateBarrageAdapter & ltBarrageData & gtmBarrageAdapterprivatebooleanisInitBarrageprivateinttouchSloop//滑动阈值privatefloatlastX//最后一个事件privatefloatlastY的坐标;privatefloatdeltaYprivatebooleanisHorizontalMove = false;privatebooleanisVerticalMove = false;privatebooleanisMove = falseprivateinclickcount = 0;//确定是点击还是双击,因为如果是双击,需要交给PhotoView处理。PrivateHandlerHandler = newqqpagehandler(this);privatestaticclass qqpagerhandlerextendshandler { privatewakreference & lt;QQPager & gtmQQPagerReferenceQQPagerHandler(qqpagerqpager){ this . mqqpagerreference = newWeakReference & lt;QQPager & gt(QQ pager);} @ OverridepublicvoidhandleMessage(message msg){ super . handle message(msg);switch(msg . what){ caseMSG _ UP:if(mqqpagereference . get()。click count = = 1)mqqpagereference . get()。dissolve();elsemQQPagerReference.get()。click count = 0;打破;} } } class textview holder rextendsbarrageadapter。BarrageViewHolder & ltBarrageData & gt{//…代码省略} class view holder rextendsbarrageadapter。barragviewholder

3.2事件分布

用过PhotoView的同学应该都知道,双击就是放大图片,所以我们既然用PhotoView,自然是这样的。以下是我们在事件分布中应该考虑的事项:

点击关闭图片预览,我们需要阻止touch事件发出,对话框会自行处理。双击交给ViewPager,然后ViewPager会交给PhotoView进行处理。水平移动就是ViewPager中的画面切换,事件交给ViewPager处理。垂直移动就是移动我们的ViewPager,这个是Dialog自己处理的,ViewPager的垂直滑动距离会影响背景的透明度。

说了这么多,我想你应该明白了。只处理单双击和纵横判断。事实就是这么简单。看看代码:

publicbooleandispatchtouevent(@ NonNullMotionEventev){ if(isHorizontalMove)return super . dispatchtouevent(ev);float curx = ev . getx();//获取当前坐标float cury = ev . gety();switch(ev . get action()){ caseMotionEvent。ACTION _ DOWN:m position . set alpha(1f);//Action_Down会触发位置文本的显示。MP osition . set visibility(view . visible);isMove = falseclick count++;//点击次数增加中断;caseMotionEvent。ACTION _ MOVE:float deltax = curX-lastX;deltaY = curY-lastY;if(Math.abs(deltaX)>touch loop | | math . ABS(deltaY)>touch loop){ is move = true;//如果滑动距离大于阈值,clickCount=0自动复位= 0;} if(math . ABS(deltaX)& lt;math . ABS(deltaY)){ isVerticalMove = true;//如果纵向距离大于ViewPager事件的横向阻断,发送mphotopager . set intercept(true);}破;caseMotionEvent。ACTION_UP:if(clickCount==1&&!isMove&&!Istchpointinview (mbarrage,(int) ev。getrawx(),(int) ev。getrawy())//发送消息mhandler。senemptymessagedelayed(msg _ up,400)如果不点击弹幕切换按钮;elseclickCount = 0;打破;} lastX = curXlastY = curYreturn super . dispatchtouchevent(ev);} publicbooleantouchevent(@ nonnullmotionevent){ switch(event . get action()){ caseMotionEvent。ACTION _ MOVE:mphotopager . scroll by(0,(int)-deltaY);//ViewPager垂直移动//setdialogbackgroundAlphaLotofSetPercent = math . ABS(mphotpager . get scroll()-0f)/mphotpager . getmeasuredheight();Log.e(标签,& # 34;偏移量:& # 34;+offset percent);if(getWindow()!=null)getWindow()。setDimAmount(1f-offset percent);打破;caseMotionEvent。ACTION _ UP:if(isVerticalMove){ if(math . ABS(mphotopager . getscrolly()-0f)& gt;SCROLL _ THRESHOlD){ SCROLL close animation();} else { roll back animation();} }破;}returnsuper.onTouchEvent(事件);}很多东西的代码的注释都很详细。这里我想补充一下:

单双击是通过QQPagerHandler延迟发送400ms来判断的,400ms内单击一次执行关闭动画,如果再点击一次就重置单击计数。QQPager在onTouchEvent处理的时候,会通过getWindow().setDimAmount(1f – offsetPercent)改变背景的透明度。竖直方向移动会阻断ViewPager事件的下发,所以,事件到最后还会交给自身处理,在手指释放的时候,如果竖直方向移动距离大于我们设置的最小滑动阈值,就执行滑动关闭动画,否则,ViewPager会回滚,移动到初始位置。

我们再来看看手势处理。双击,水平移动和垂直移动:

3.3动画处理

预览图片需要两种动画,视图动画和属性动画。当QQPager打开和关闭时,使用查看动画。具体可以参考上面BasePager的show()方法和set样式,这里就不介绍了。动画使用的场景是位置文本的定时显示、ViewPager的回滚和滑动退出。代码是类似的,所以这里是滑动出口:

privatevoidscrollCloseAnimation(){ window window = getWindow();如果(窗口!= null)window . setdimamount(0f);if(deltaY & gt;0){mPhotoPager.animate()。y(mphotopager . getmeasuredheight())。setDuration(600)。set listener(newSimpleAnimationListener(){ @ overridepublicvodonanimationend(animator animation){ super . on animation end(animation);//getWindow()。setWindowAnimations(r . style . photopageralpha);dissolve();}}).start();}else{mPhotoPager.animate()。y(-mphotopager . getmeasuredheight())。setDuration(600)。set listener(newSimpleAnimationListener(){ @ overridepublicvodonanimationend(animator animation){ super . on animation end(animation);//getWindow()。setWindowAnimations(r . style . photopageralpha);dissolve();}}).start();}}不得不说,利用View本身的animate()来使用属性动画还是挺方便的。一用就爽,每次用都爽~

「4.PhotoPagerViewProxy】

最后,让我们介绍以下代理类,它们主要用于构建数据:

publicclassPhotoPagerViewProxyimplementsIPhotoPager { publicstaticfinalintTYPE _ NORMAL = 1;publistaticfinalinttype _ QQ = 2;publistaticfinalinttype _ WE _ CHAT = 3;publistaticfinalintanimation _ SCALE _ ALPHA = 1;publistaticfinalintanimation _ TRANSLATION = 2;publistaticfinalintanimation _ ALPHA = 3;privateBasePagerphotoPageViewprivateophopagerviewproxy(context context,inttype,config config){ switch(type){ caseTYPE _ QQ:photoPageView = newqq pager(context,r . style . dialog);打破;caseTYPE _ WE _ CHAT:break;default:photo pageview = newNormalPager(context,r . style . dialog);打破;}setConfig(配置);} @ Overridepublicvoidshow(){ photopage view . show();} @ overridepublicvoiddisse(){ photopage view . disse();} @ OverridepublicvoidsetConfig(config config){ photopageview . set config(config);} publistaticlassbuilder { privateActivitycontext;privateIPhotoPager。ConfigconfigprivateinttypepublicBuilder(Activitycontext,int type){ this . context = context;this.config=newIPhotoPager。config();this.type = type} public builder(activity context){//defaulttypeisTYPE _ NORMAL this(context,TYPE _ NORMAL);}//…同样省略一大段代码,你只需要知道这里是初始化数据,使用的构建器模式是publicphotopageservieproxy create(){ ReturnNewPhotoPageServieProxy(context,type,config);}}}三。总结一般来说,代码量小,不难。但是,这段代码仍然需要改进。例如,背景透明度不会随着ViewPager的垂直滑动距离而快速变化。当然,我的水平有限,难免会出错。如果你发现任何问题,请纠正我。

Over~演示地址:https://github.com/mCyp/PhotoPagerView

Android核心知识点笔记GitHub:https://github.com/AndroidCot/Android

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/284447.html

发表回复

登录后才能评论