Android仿即刻首页垂直滚动图,炫酷到底!
项目地址:https://github.com/jeasonwong/jikegallery
话不多说,先上效果。
这个效果是在即刻app上看到,觉得很不错,遂仿之。
先说下我的实现思路(以上方的图片滚动为例,下方的文字实现效果类似):
自定义viewgroup
装载两个imageview和一个阴影view
通过一定规律交替控制两个imageview和它们的margintop,在onlayout()中实现
margintop的具体值由属性动画控制,不断调用requestlayout()
接下来依次说明
一、自定义viewgroup
//滑动状态 protected static final int status_smoothing = 0; //停止状态 protected static final int status_stop = 1; //viewgroup宽高 protected int mwidth, mheight; //变化的margintop值 protected int msmoothmargintop; //默认状态 protected int mstatus = status_stop; //滚动时间间隔 protected int mduration = 500; //重复次数 protected int mrepeattimes = 0; ... @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); mwidth = w; mheight = h; msmoothmargintop = -h; initview(); } protected abstract void initview(); ... /** * 是否是奇数圈 * * @return 结果 */ protected boolean isoddcircle() { return mrepeattimes % 2 == 1; }
先了解下成员变量,其中最重要的一个就是msmoothmargintop,相信很多人都知道一个view的margintop可以设为负数,这个负数可以给我们带来太多的方便。
上图的图0就是我们展现在屏幕上的imageview,图1则是屏幕外margintop为-height的imageview,这个一定要明白,接下来才好继续实现。
二、装载两个imageview和一个阴影view
private list<string> mimglist = new arraylist<>(); private imageview[] mimgs = new imageview[2]; private view mshadowview; ... @override protected void initview() { //如果没有内容,则不进行初始化操作 if (mimglist.size() == 0) { return; } removeallviews(); marginlayoutparams params = new marginlayoutparams(mwidth, mheight); //两个imageview加载前两张图 for (int i = 0; i < mimgs.length; i++) { mimgs[i] = new imageview(getcontext()); addviewinlayout(mimgs[i], -1, params, true); glide.with(getcontext()).load(getimgpath(i)).centercrop().into(mimgs[i]); } //创建阴影view mshadowview = new view(getcontext()); mshadowview.setbackgroundcolor(color.parsecolor("#60000000")); mshadowview.setalpha(0); addviewinlayout(mshadowview, -1, params, true); } ... /** * 获取图片地址 * * @param position 位置 * @return 图片地址 */ private string getimgpath(int position) { position = position % mimglist.size(); return mimglist.get(position); }
关键点说明:
marginlayoutparams 为了之后方便取出margin值
addviewinlayout() 为了对requestlayout的绝对控制
getimgpath() 为了实现循环滚动
这样一来,我们需要的view都已经创建好了。
三、通过一定规律交替控制两个imageview和它们的margintop,在onlayout()中实现
@override protected void onlayout(boolean changed, int l, int t, int r, int b) { int ccount = getchildcount(); marginlayoutparams cparams; for (int i = 0; i < ccount; i++) { view childview = getchildat(i); cparams = (marginlayoutparams) childview.getlayoutparams(); int cl = 0, ct = 0, cr, cb; if (isoddcircle()) { if (i == 1) { cl = cparams.leftmargin; ct = msmoothmargintop + mheight; } else if (i == 0) { cl = cparams.leftmargin; ct = msmoothmargintop; } } else { if (i == 0) { cl = cparams.leftmargin; ct = msmoothmargintop + mheight; } else if (i == 1) { cl = cparams.leftmargin; ct = msmoothmargintop; } } //控制shadowview if (i == 2) { cl = cparams.leftmargin; ct = msmoothmargintop + mheight; } cr = cl + mwidth; cb = ct + mheight; childview.layout(cl, ct, cr, cb); } }
以上实现的就是不断的替换图1和图2谁上谁下,阴影和下方的图保持同步。
四、margintop的具体值由属性动画控制,不断调用requestlayout()
先看基类viewgroup
/** * 开启滑动 * */ public void startsmooth() { if (mstatus != status_stop) { return; } valueanimator animator = valueanimator.offloat(-mheight, 0); animator.setduration(mduration); animator.setinterpolator(new acceleratedecelerateinterpolator()); animator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { float margintop = (float) animation.getanimatedvalue(); msmoothmargintop = (int) margintop; if (margintop == 0) { postdelayed(new runnable() { @override public void run() { mrepeattimes++; msmoothmargintop = -mheight; doanimfinish(); mstatus = status_stop; } }, 50); } else { doanim(); } } }); animator.start(); mstatus = status_smoothing; } //动画结束 protected abstract void doanimfinish(); //动画进行时 protected abstract void doanim();
关键点说明:
属性动画控制着msmoothmargintop在[-mheight, 0]中变化
每完成一圈,mrepeattimes自增1
再来看看gallery实现类
@override protected void doanimfinish() { if (isoddcircle()) { glide.with(getcontext()).load(getimgpath(mrepeattimes + 1)).centercrop().into(mimgs[0]); } else { glide.with(getcontext()).load(getimgpath(mrepeattimes + 1)).centercrop().into(mimgs[1]); } mshadowview.setalpha(0); } @override protected void doanim() { mshadowview.setalpha(((1 - (-msmoothmargintop) / (float) mheight))); requestlayout(); }
关键点说明:
通过msmoothmargintop与mheight的比值控制阴影view的透明度
每次动画完成时,下方的图(此时下方的图已经超出屏幕了,而上方图显示在屏幕内)需要加载第三张图,使用getimgpath()取出
pic1
以上就是图片的滚动实现,文字的滚动90%是一样的,有点区别的就是需要文字需要控制下垂直居中,我就不赘述了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。