欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿即刻首页垂直滚动图,炫酷到底!

程序员文章站 2024-03-06 18:27:14
项目地址:https://github.com/jeasonwong/jikegallery 话不多说,先上效果。 这个效果是在即刻app上看到,觉得很不错,遂仿之...

项目地址:https://github.com/jeasonwong/jikegallery

话不多说,先上效果。

Android仿即刻首页垂直滚动图,炫酷到底!

这个效果是在即刻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可以设为负数,这个负数可以给我们带来太多的方便。

Android仿即刻首页垂直滚动图,炫酷到底!

上图的图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

Android仿即刻首页垂直滚动图,炫酷到底!

以上就是图片的滚动实现,文字的滚动90%是一样的,有点区别的就是需要文字需要控制下垂直居中,我就不赘述了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。