Android实现知乎选项卡动态隐藏效果实例

 更新时间:2018年02月03日 15:41:17   作者:达峰a  
选项卡相信对大家来说应该不陌生,最近发现知乎选项卡的动态隐藏效果不错,下面这篇文章主要给大家介绍了关于Android实现知乎选项卡动态隐藏效果的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。

前言

因为最近手上项目也是资讯阅读类,简书,掘金,知乎的效果都想往项目上加,没事就来仿写。


选项卡动态隐藏.gif

效果呢,和知乎首页一样,可以去知乎看看;点击back键可以返回顶部。下面话不多说了,来一起看看详细的介绍吧。

想法:

  • 列表上拉,选项卡隐藏,下滑出现;recycleView滚动监听(OnScrollListener)中onScrolled方法的dy参数,dy>0表示上拉,dy<0表示下滑,刚好合适。
  • 选项卡怎么隐藏呢,属性动画,移动选项卡的相对位置View.TRANSLATION_Y(Y轴方向移动肯定是_Y),View.TRANSLATION系列都是相对运动,参考系是view原本的位置。
  • 还有个问题,对于选项卡来说,它需要的显隐时机是列表滑动方向改变,而不是只监听它的滑动;上拉改下滑,下滑改上拉这2个时机才能执行动画,不能在列表同一方向持续滚动时重复调用动画。

步骤:

要写多少代码呢? fragmeng中一个recycleView的监听要写,一个接口要写;activity中接口实现。没了,代码不多。

Fragment:

public interface RvScrollListener {
 //滑动方向监听
 void scrollType(boolean direction);
 //是否滑动到顶部监听
 void inTop(boolean top,RecyclerView recyclerView);
}

private RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
 @Override
 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
  super.onScrollStateChanged(recyclerView, newState);
  if (fragmentposition != 0) {
   //如果不是第一个fragment则返回
   return;
  }
  LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  //得到当前列表第一个完全显示的item的position
  int position = layoutManager.findFirstCompletelyVisibleItemPosition();
  if (position == 0) {
   //如果position为0表示列表正处于顶部
   mRvScrollListener.inTop(true, recyclerView);
  } else {
   mRvScrollListener.inTop(false, recyclerView);
  }
 }

 @Override
 public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
  super.onScrolled(recyclerView, dx, dy);
  //判断滑动方向,recycleView item 上拉 下滑不同动画
  if (dy > 0) {
   isUp = true;
  } else {
   isUp = false;
  }

  if (fragmentposition != 0) {
   return;
   //如果不是第一个fragment则返回
  }
  //过滤掉一些缓慢的滑动
  if (Math.abs(dy) > 10) {
   //滑动方向
   mRvScrollListener.scrollType(dy > 0);
  }
 }
};

recycleView第一个监听方法:

@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {}

这个里面就做一件事情,判断当前recycleView是否滑动到顶部,然后通过接口传递到activity中,当点击back键时,如果不在顶部,则调用方法滚动到顶部。

recycleView第二个监听方法:

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {}

做2件事,一是recyleView的item做动画时,因为上拉和下滑动画不一样,代码中 isUp 就是用来区分上拉下滑的((给recycleView的item做加载动画使用));

二是判断滑动方向,接口传递到activity中。

Activity:

//上拉状态
private boolean hasup = true;
//下滑状态
private boolean hasdown = true;
//是否在顶部
private boolean inTop = true;
//从fragment传递过来的recycleView
private RecyclerView topRecyclerView;
BlankFragment.RvScrollListener mRvScrollListener = new BlankFragment.RvScrollListener() {

 @Override
 public void scrollType(boolean direction) {
  //上拉
  if (direction) {
   hasdown = true;
   //连续上拉,第一次有效
   if (hasup) {
    ObjectAnimator.ofFloat(mTablayout, View.TRANSLATION_Y, mTablayout.getTranslationY(), PixelChange.dp2px(XjwTablayoutActivity.this, 50)).setDuration(400).start();
    hasup = false;
   }
  } else {//下滑
   hasup = true;
   //连续下滑,第一次有效
   if (hasdown) {
    ObjectAnimator.ofFloat(mTablayout, View.TRANSLATION_Y, mTablayout.getTranslationY(), 0).setDuration(400).start();
    hasdown = false;
   }
  }
 }

 @Override
 public void inTop(boolean top, RecyclerView recyclerView) {
  inTop = top;
  topRecyclerView = recyclerView;
 }
};

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
 //点击返回键
 if (keyCode == KeyEvent.KEYCODE_BACK) {
  //如果当前不是第一个fragmeng则显示第一个
  if (mViewPager.getCurrentItem() != 0) {
   mViewPager.setCurrentItem(0);
   return true;
  }
  //如果当前recycleView没有在顶部则返回顶部
  if (!inTop) {
   topRecyclerView.smoothScrollToPosition(0);
   return true;
  }
 }
 return super.onKeyDown(keyCode, event);
}

实现接口第一个方法:

@Override
public void scrollType(boolean direction) {}

方法里用到三个boolean值 direction ,hasup, hasdown ,direction判断执行上拉动画或者下滑动画;hasup和hasdown作用是:滑动有上拉,下滑2个状态,处于一种状态时动画只执行一次;比如列表正在持续上拉,监听也会触发多次,上拉的多次触动中只执行一次动画。

实现接口第二个方法:

@Override
public void inTop(boolean top, RecyclerView recyclerView) {}

就一个赋值作用,用在back键的点击事件中onKeyDown。

back键点击

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {}

一点需要注意:recycleView滚动到顶部,调用的是smoothScrollToPosition()方法,这个最简单,调用别的方法譬如smoothScrollBy() ,还需要算距离,不过这个方法可以给插值器。

属性动画

//隐藏
ObjectAnimator.ofFloat(mTablayout, View.TRANSLATION_Y, mTablayout.getTranslationY(), PixelChange.dp2px(XjwTablayoutActivity.this, 50)).setDuration(400).start();
//显示
 ObjectAnimator.ofFloat(mTablayout, View.TRANSLATION_Y, mTablayout.getTranslationY(), 0).setDuration(400).start();

注意2个点,一个是 View.TRANSLATION_Y 这个参数要写对,

另外一个是动画的起始值:

如果隐藏动画是从0dp移动到50dp,快速切换上拉下滑状态时(手指快速上下滑动)控件就会闪。所以隐藏动画中从 mTablayout.getTranslationY()的位置移动到 50 dp的位置,动态获取当前选项卡位置就好了,显示动画同理。(写50dp是因为我选项卡高度就是50dp)

另外把recycleView的item加载动画代码给出来:(这个写在Adapter里面的,因为要在onBindViewHolder时调用)

protected Animator[] getAnimators(View view) { //上滑动画
 return new Animator[]{
   ObjectAnimator.ofFloat(view, View.ROTATION, 120, 0).setDuration(400)
 };
}

protected Animator[] getAnimatorsDown(View view) { //下拉动画
 return new Animator[]{
   ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -100, 0).setDuration(400),
   ObjectAnimator.ofFloat(view, View.SCALE_X, 0.7f, 1f).setDuration(400)
 };
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
 if (isUp) { //上拉
  Animator[] animators = getAnimators(holder.itemView);
  if (animators.length > 1) {
   AnimatorSet animatorSet = new AnimatorSet();
   animatorSet.playTogether(animators);
   animatorSet.start();
  } else {
   for (Animator annimator : animators) {
    annimator.start();
   }
  }
 } else {//下拉
  Animator[] animatorsDown = getAnimatorsDown(holder.itemView);
  if (animatorsDown.length > 1) {
   AnimatorSet animatorSet = new AnimatorSet();
   animatorSet.playTogether(animatorsDown);
   animatorSet.start();
  } else {
   for (Animator annimator : animatorsDown) {
    annimator.start();
   }
  }
 }
}

item加载动画和选项卡显隐动画差不多,你可以把 View.SCALE_X 这种参数改一改,多试试效果,注意起始值。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • Android自定义View之酷炫圆环(二)

    Android自定义View之酷炫圆环(二)

    这篇文章主要介绍了Android自定义View之酷炫圆环,本文是第二篇针对Android圆环实现方法进行的详细阐述,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • 更新Android Studio 3.0碰到的问题小结

    更新Android Studio 3.0碰到的问题小结

    本文是小编给大家分享的更新Android Studio 3.0碰到的问题小结,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-11-11
  • Android Touch事件分发过程详解

    Android Touch事件分发过程详解

    这篇文章主要介绍了Android Touch事件分发过程,详细描述了Android Touch事件的主要处理流程,有助于深入理解Android程序设计,需要的朋友可以参考下
    2014-09-09
  • Moshi 完美解决Gson在kotlin中默认值空的问题详解

    Moshi 完美解决Gson在kotlin中默认值空的问题详解

    这篇文章主要为大家介绍了Moshi 完美解决Gson在kotlin中默认值空的问题详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Android 手写RecyclerView实现列表加载

    Android 手写RecyclerView实现列表加载

    这篇文章主要介绍了Android 手写RecyclerView实现列表加载,涉及到列表的需求,肯定第一时间想到RecyclerView,即便是自定义View,那么RecyclerView也会是首选,为什么会选择RecyclerView而不是ListView,主要就是RecyclerView的内存复用机制,这也是RecyclerView的核心 
    2022-08-08
  • 微信举报解除和微信解除限制的6个方法

    微信举报解除和微信解除限制的6个方法

    本文主要介绍微信被举报怎么解除?微信解除限制,这里整理了6种方法,有需要的小伙伴可以参考下
    2016-09-09
  • Android自定义TextBanner实现自动滚动

    Android自定义TextBanner实现自动滚动

    这篇文章主要为大家详细介绍了Android自定义TextBanner实现自动滚动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • Android开发之电话拨号器和短信发送器实现方法

    Android开发之电话拨号器和短信发送器实现方法

    这篇文章主要介绍了Android开发之电话拨号器和短信发送器实现方法,结合实例形式较为详细的分析了Android电话拨号器和短信发送器的具体原理与实现步骤,需要的朋友可以参考下
    2015-12-12
  • Android WebView 优化之路

    Android WebView 优化之路

    Android WebView 优化之路,如何才能更有效的对Android WebView进行优化,本文将为大家一一举例,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • Android使用MediaRecorder实现录像功能

    Android使用MediaRecorder实现录像功能

    这篇文章主要为大家详细介绍了Android使用MediaRecorder实现录像功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06

最新评论