博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
漂亮的ActionBar效果
阅读量:7075 次
发布时间:2019-06-28

本文共 6200 字,大约阅读时间需要 20 分钟。

Newsstand—这个应用引进了新的方式,使得ActionBar达到了新的水平。如果你打开这个应用的发布页,你会注意到不带图标的ActionBar是半透明的,而且和一个大的图片集(一个大的杂志图标,描述了一些新闻)交叠在一起。一旦你开始下滑,大杂志图标会位移并缩放,以匹配ActionBar的图标所在。

这样做的主要优势是使ActionBar真正成为内容的一部分。

在这篇文章中,我主要解释一下如何制作整个发布页面(ActionBar效果和动画)。我将详细介绍一下ActionBar效果的实现细节。我将解释一下如何创建带有Ken Burns动画的视图。

ActionBar效果

风格

第一步是设置风格:

  • 半透明ActionBar
  • 启用overlay模式
  
  
  

布局结构

布局结构真的很重要。主要布局是一个FrameLayout,包含一个ListView和另一个FrameLayout(如header)。这个Header包含两个ImageView(如header_picture和header_logo),前者是一个普通的图片,后者是将要位移并缩放到ActionBar的图标。

  
    
    
  

这的效果是在ListView中添加一个伪header。这个伪header必须和真正的header拥有相同的高度。你可以使用如下布局来描述这个伪header:

之后,你必须用代码填充和添加伪header:

mFakeHeader = getLayoutInflater().inflate(R.layout.fake_header, mListView, false); mListView.addHeaderView(mFakeHeader);

获取滚动位置

这个我将详细解释,因为有大量的关于滚动位置获取的StackOverflow帖子。

public int getScrollY() {   View c = mListView.getChildAt(0);   if (c == null) {
    return 0;   }   int firstVisiblePosition = mListView.getFirstVisiblePosition();   int top = c.getTop();   int headerHeight = 0;   if (firstVisiblePosition >= 1) {
   headerHeight = mPlaceHolderView.getHeight();   }     return -top + firstVisiblePosition * c.getHeight() + headerHeight; }

有一点请注意:如果ListView第一个可见item的索引不小于1的话,你必须在计算中关注header的高度。

平移header

在ListView的滑动过程中,为了赶得上ListView的伪header,你必须平移真的header。请注意:平移必须和ActionBar的高度绑定在一起。

mListView.setOnScrollListener(new AbsListView.OnScrollListener(){
   @Override    public void onScrollStateChanged(AbsListView view, int scrollState){ }    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount){
     int scrollY = getScrollY();      //sticky actionbar     mHeader.setTranslationY(Math.max(-scrollY, mMinHeaderTranslation));    } } );

标题可见性

为了达到渐变的效果,你需要检索标题View。这个视图可以通过使用Resources.getIdentifier方法检索到。

private TextView getActionBarTitleView() {   int id = Resources.getSystem().getIdentifier("action_bar_title", "id", "android");   return (TextView) findViewById(id); }

然后,只要初始化这个View的alpha值:

getActionBarTitleView().setAlpha(0f);

在ListView的滚动过程中,你必须依据header的平移率来渐变这个视图的可见性

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {  @Override   public void onScrollStateChanged(AbsListView view, int scrollState) {  }  @Override   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {    float ratio = clamp(mHeader.getTranslationY() / mMinHeaderTranslation, 0.0f, 1.0f); //actionbar title alpha     getActionBarTitleView().setAlpha(clamp(5.0F * ratio - 4.0F, 0.0F, 1.0F));   } });

Alpha值:f(x)=5x-4:

这个钳位方法是基本的Math方法();

public static float clamp(float value, float max, float min) {
  return Math.max(Math.min(value, min), max); }

来自Cyril Mottier的更好的解决方案

首先,你不必再获取ActionBar的标题视图的引用了。我们将要使用带有自定义ForegroundColorSpan()的SpannableString()。我们需要自定义的能够设置颜色可见性的ForegroundColorSpan:

public class AlphaForegroundColorSpan extends ForegroundColorSpan {   private float mAlpha;   public AlphaForegroundColorSpan(int color) {     super(color);    } […]   @Override   public void updateDrawState(TextPaint ds) {     ds.setColor(getAlphaColor());   }   public void setAlpha(float alpha) {
    mAlpha = alpha;   }  public float getAlpha() {     return mAlpha;   }   private int getAlphaColor() {
    int foregroundColor = getForegroundColor();     return Color.argb((int) (mAlpha * 255), Color.red(foregroundColor), Color.green(foregroundColor), Color.blue(foregroundColor));   } }

在ListView的滚动过程中,我们在AlphaForegroundColorSpan对象上设置alpha值并最终调用ActionBar.setTitle来刷新标题视图。请注意:考虑到性能(避免GC),你必须保持相同的AlphaForegroundColorSpan和SpannableString对象。

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
  @Override   public void onScrollStateChanged(AbsListView view, int scrollState) { }   @Override   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {     float ratio = clamp(mHeader.getTranslationY() / mMinHeaderTranslation, 0.0f, 1.0f);     //actionbar title alpha     setTitleAlpha(clamp(5.0F * ratio – 4.0F, 0.0F, 1.0F));     }   });     private void setTitleAlpha(float alpha) {
      mAlphaForegroundColorSpan.setAlpha(alpha);       mSpannableString.setSpan(mAlphaForegroundColorSpan, 0, mSpannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);       getActionBar().setTitle(mSpannableString);   }

移动并缩放图标

要实现平移,你需要检索到图标视图。这个视图可以通过经典的findViewById方法来实现。

private ImageView getActionBarIconView() {
  return (ImageView) findViewById(android.R.id.home); }

然后,在ActionBar上设置透明的图标。

ActionBar actionBar = getActionBar(); actionBar.setIcon(R.drawable.ic_transparent);

在ListView滚动的过程中,你必须依赖于header的平移率来移动并缩放图标视图。主要原则是在透明可变的ActionBar图标视图和header的logo视图之间产生”diff”。这个”diff”是使用两个屏幕上的Rect来计算的,并且这个”diff”产生scaleX, scaleY,translationX和translationY值。最终,这些值用于平移和缩放header的logo视图,直到logo视图匹配了透明度可变的ActionBar图标视图。

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {   @Override   public void onScrollStateChanged(AbsListView view, int scrollState) { }   @Override   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    float ratio = clamp(mHeader.getTranslationY() / mMinHeaderTranslation, 0.0f, 1.0f); //move & scale     interpolation = mAccelerateDecelerateInterpolator.getInterpolation(ratio);     View actionBarIconView = getActionBarIconView();     getOnScreenRect(mRect1, mHeaderLogo);     getOnScreenRect(mRect2, actionBarIconView);     float scaleX = 1.0F + interpolation (mRect2.width() / mRect1.width() – 1.0F);     float scaleY = 1.0F + interpolation (mRect2.height() / mRect1.height() – 1.0F);     float translationX = 0.5F (interpolation (mRect2.left + mRect2.right – mRect1.left – mRect1.right));     float translationY = 0.5F (interpolation (mRect2.top + mRect2.bottom – mRect1.top – mRect1.bottom));     mHeaderLogo.setTranslationX(translationX);     mHeaderLogo.setTranslationY(translationY – mHeader.getTranslationY());     mHeaderLogo.setScaleX(scaleX); mHeaderLogo.setScaleY(scaleY);   } });

请注意:为了使动画更顺滑,你可以在平移率上使用AccelerateDecelerateInterpolator。

 

Ken Burns动画

代码地址:

总结

正如此处所言,问题有不同实现方式的称为“同步滚动”的伎俩。

转载地址:http://etdml.baihongyu.com/

你可能感兴趣的文章
PhoneGap安装配置
查看>>
C# DataGridView中合并单元格
查看>>
WinXP 无线技巧“区域没有通过无线网络中的发现”一个可能的原因!
查看>>
chrome(转)
查看>>
Java知多少(90)菜单
查看>>
基本语法 protocols Category extension
查看>>
切割图像(一)概要
查看>>
shell重定向
查看>>
系列文章--Python Web编程
查看>>
Swift - 搜索条(UISearchBar)的用法
查看>>
iOS开发之ImageView复用实现图片无限轮播
查看>>
文件系统中的目录查找
查看>>
openwrt-智能路由器hack技术(1)---"DNS劫持"
查看>>
第十二章 数据备份与还原
查看>>
[redis] Redis 配置文件置参数详解
查看>>
Java 多线程程序设计
查看>>
BZOJ4347 : [POI2016]Nim z utrudnieniem
查看>>
jquery validate自定义checkbox验证规则和样式
查看>>
WPF自定义控件与样式(14)-轻量MVVM模式实践
查看>>
EF Code First学习系列
查看>>