Android渐变标题栏的实现

Android4.4以上推出了Toolbar,改变程序的style属性就可以给手机的标题栏填充颜色,可以是你设置好的系统的主题色,也可以是自己填充的颜色,其实这个效果在iOS早就有了,但在Android中还是很少见的。在iOS中,最常见的Navigationbar的效果就是一个转场动画(多出现于两个界面切换的时候),一个就是随着手势滑动背景渐变(多出现于详情页)。今天我们就来实现下大多出现于详情页的这个渐变效果的标题栏。
具体效果见:点击打开链接

接下来我们就来实现这个效果。
首先,我们要先把手机上面的状态栏的颜色背景隐藏掉,在这里会有一个坑,在小米和魅族手机里,好想说是MIUI6以上,上面状态栏上的时间啊什么的文字默认的颜色是白色,如果你的Toolbar的背景是相对深颜色的话,是没有问题的,但是如果你的Toolbar是相对浅的背景颜色,那么很可能这些时间文字会显示不出来,那么就要修改上面状态栏的颜色了。具体可以参考这篇:点击打开链接
先在style里设置,这是我的style.xml:

<resources>  
  
    <style name="AppTheme" parent="Theme.AppCompat.Light">  
        <!-- Customize your theme here. -->  
        <item name="android:windowBackground">@color/devide</item>  
        <item name="windowActionBar">false</item>  
        <item name="windowNoTitle">true</item>  
        <item name="android:windowNoTitle">true</item>  
        <item name="android:textColorSecondary">@color/white</item>  
        <item name="android:textColorPrimary">@color/white</item>  
        <item name="toolbarStyle">@style/ToolbarStyle</item>-  
        <item name="colorControlNormal">@android:color/white</item>  
    </style>  
  
    <style name="ToolbarStyle" parent="Widget.AppCompat.Toolbar">  
        <item name="contentInsetStart">0dp</item>  
        <item name="colorControlNormal">@android:color/white</item>  
    </style>  
  
</resources>  

接下来我们就要把状态栏设置为透明:

private void setTranslucentWindows(Activity activity) {  
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {  
            //透明状态栏  
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);  
        }  
    }  

以下是我写的标题栏的布局文件:

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout  
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content">  
  
    <RelativeLayout  
        android:id="@+id/layout_toolbar_my_container"  
        android:fitsSystemWindows="true"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:background="@color/base"  
        android:paddingBottom="0dp">  
  
        <android.support.v7.widget.Toolbar  
            android:layout_width="match_parent"  
            android:layout_height="44dp"  
            android:elevation="0dp">  
  
            <RelativeLayout  
                android:layout_width="match_parent"  
                android:layout_height="match_parent">  
  
                <RelativeLayout  
                    android:id="@+id/layout_toolbar_details_back"  
                    android:layout_width="60dp"  
                    android:onClick="onBack"  
                    android:layout_height="match_parent">  
  
                    <ImageView  
                        android:layout_width="wrap_content"  
                        android:layout_height="wrap_content"  
                        android:layout_centerVertical="true"  
                        android:layout_marginLeft="10dp"  
                        android:src="@mipmap/btn_back" />  
  
                </RelativeLayout>  
  
                <TextView  
                    android:visibility="gone"  
                    android:id="@+id/text_toolbar_index"  
                    android:layout_centerInParent="true"  
                    android:layout_width="wrap_content"  
                    android:layout_height="wrap_content"  
                    android:text="我是一个标题"  
                    android:textColor="@color/white"  
                    android:textSize="17dp" />  
  
            </RelativeLayout>  
  
        </android.support.v7.widget.Toolbar>  
  
    </RelativeLayout>  
  
</RelativeLayout>  

将标题栏的布局文件引入到我们界面的布局文件里,我们是相当于在recyclerView的header上叠加了一层透明的标题栏,这里对recyclerView的adapter的所有操作我都集成了一个通用格式来进行操作,方便很多。我给recyclerView添加了一个header,在这里为了简便,用imageView来代替了轮播图。为了达到渐变的效果,我们要去监听滑动事件,是否滑动到imageView的高度,也就是把imageView隐藏,当正好隐藏的时候标题栏的文字将出现(这个一般看交互,如果大图下面有标题,一般建议标题覆盖以后,标题栏上的标题再显示),当前的y与整体要滑动距离的百分比来控制标题栏的背景透明度。在这里要注意,当onCreate方法的时候,一个view的getMeasuredHeight()方法或者宽度的方法获得的都是0,因为这个时候你的view还没有draw上去,只有当onCreate方法执行完了以后,控件才会被onMeasure。所以有两种策略,一种是我以下代码实现的,等view的onMeasure好了以后再去调用方法,还有一种是去注册一个ViewTreeObserver的监听回调,具体大家可以去自行百度。ok,下面贴上Activity里的代码:

public class MainActivity extends AppCompatActivity {  
  
    @Bind(R.id.recycler)  
    RecyclerView recyclerView;  
    @Bind(R.id.layout_toolbar_my_container)  
    RelativeLayout layoutToolBarBackground;  
    @Bind(R.id.text_toolbar_index)  
    TextView centerText;  
  
    private ArrayList<Model> modelList = new ArrayList<>();  
    private MyRecyclerAdapter adapter;  
    private LinearLayoutManager layoutManager;  
    private int itemIndex;  
    private ToolBarBackgroundController toolBarBackgroundController;  
    private int anchorHeight;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        setTranslucentWindows(this);  
        ButterKnife.bind(this);  
        layoutManager = new LinearLayoutManager(this.getApplicationContext());  
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);  
        recyclerView.setLayoutManager(layoutManager);  
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST,  
                R.drawable.devide_line_gray, 0));  
        initHead();  
        initData();  
        initView();  
    }  
  
    private void initHead() {  
        layoutToolBarBackground.setBackgroundColor(Color.TRANSPARENT);  
        toolBarBackgroundController = new ToolBarBackgroundController(layoutToolBarBackground);  
    }  
  
    public class ToolBarBackgroundController {  
  
        private View layoutToolbar;  
  
        public ToolBarBackgroundController(View layoutToolbar) {  
            this.layoutToolbar = layoutToolbar;  
            layoutToolbar.setBackgroundColor(Color.TRANSPARENT);  
        }  
  
        public void setTransparent(boolean needTransparent) {  
            if (needTransparent) {  
                //变透明  
                centerText.setVisibility(View.GONE);  
            } else {  
                layoutToolbar.setBackgroundColor(getResources().getColor(R.color.base));  
                centerText.setVisibility(View.VISIBLE);  
            }  
        }  
    }  
  
    private void setTranslucentWindows(Activity activity) {  
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {  
            //透明状态栏  
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);  
        }  
    }  
  
    private int getStatusBarHeight(Context context) {  
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");  
        if (resourceId > 0) {  
            return context.getResources().getDimensionPixelSize(resourceId);  
        } else return 0;  
    }  
  
    private void initData() {  
        for (int i = 0; i < 20; i++) {  
            Model model = new Model();  
            model.setName("jjq" + i);  
            model.setDesc("哈哈哈哈哈哈哈哈");  
            modelList.add(model);  
        }  
    }  
  
    private void initView() {  
        if (adapter == null) {  
            adapter = new MyRecyclerAdapter();  
        } else {  
            adapter.notifyDataSetChanged();  
        }  
        adapter.initData(false);  
        adapter.appendData(modelList);  
        recyclerView.setAdapter(adapter);  
        recyclerView.addOnScrollListener(new OnScrollColorChangeListener());  
    }  
  
    private class OnScrollColorChangeListener extends RecyclerView.OnScrollListener {  
  
        private boolean isTrans = true;  
        private int y = 0;  
  
        @Override  
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {  
            super.onScrolled(recyclerView, dx, dy);  
            if (anchorHeight != 0) {  
                y += dy;  
                boolean needTrans = y <= anchorHeight;  
                if (needTrans != isTrans) {  
                    isTrans = needTrans;  
                    toolBarBackgroundController.setTransparent(needTrans);  
                } else {  
                    if (y / anchorHeight < 1) {  
                        layoutToolBarBackground.setBackgroundColor(getResources().getColor(R.color.base));  
                        layoutToolBarBackground.getBackground().setAlpha((int) ((float) y / anchorHeight * 255));  
                    }  
                }  
            }  
        }  
    }  
  
    private class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  
        private final int TYPE_HEADER = 0x1000;  
        private final int TYPE_NORMAL = 0x2000;  
        private final int TYPE_FOOTER = 0x3000;  
        private final int TYPE_EMPTY = 0x4000;  
        private final int TYPE_THEME = 0x5000;  
        private ArrayList<MyItemInfo> itemInfos;  
        private boolean needFooter = false;  
        private boolean hasFooter = false;  
  
        public class MyItemInfo {  
            int type;  
            Model model;  
  
            public MyItemInfo(int type, Model model) {  
                this.type = type;  
                this.model = model;  
            }  
        }  
  
        public MyRecyclerAdapter() {  
            itemInfos = new ArrayList<>();  
        }  
  
        public void initData(boolean needFooter) {  
            this.needFooter = needFooter;  
            this.hasFooter = false;  
            int oldCount = itemInfos.size();  
            itemInfos.clear();  
            this.notifyItemRangeRemoved(0, oldCount);  
            itemInfos.add(new MyItemInfo(TYPE_HEADER, null));  
            //itemInfos.add(new MyItemInfo(TYPE_FOOTER, null));  
            //this.notifyItemRangeInserted(0, 2);  
        }  
  
        public void appendData(ArrayList<Model> models) {  
            int oldCount = itemInfos.size();  
            if (hasFooter) {  
                itemInfos.remove(oldCount - 1);  
                this.notifyItemRemoved(oldCount - 1);  
                oldCount--;  
            }  
            int size = models.size();  
            for (int i = 0; i < size; i++) {  
                itemInfos.add(new MyItemInfo(TYPE_NORMAL, models.get(i)));  
            }  
  
            this.notifyItemRangeInserted(oldCount + 1, size);  
            if (needFooter) {  
                itemInfos.add(new MyItemInfo(TYPE_FOOTER, null));  
                this.notifyItemInserted(itemInfos.size() - 1);  
                hasFooter = true;  
            }  
        }  
  
        public void removeFooter() {  
            int oldCount = itemInfos.size();  
            itemInfos.remove(oldCount - 1);  
            notifyItemRemoved(oldCount - 1);  
        }  
  
        public void appendEmptyView() {  
            int oldCount = itemInfos.size();  
            if (hasFooter) {  
                itemInfos.remove(oldCount - 1);  
                this.notifyItemRemoved(oldCount - 1);  
                oldCount--;  
            }  
            itemInfos.add(new MyItemInfo(TYPE_EMPTY, null));  
            notifyItemRangeInserted(oldCount, 1);  
        }  
  
        @Override  
        public int getItemViewType(int position) {  
            return itemInfos.get(position).type;  
        }  
  
        @Override  
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());  
            View view = null;  
            switch (viewType) {  
                case TYPE_HEADER:  
                    view = inflater.inflate(R.layout.layout_main_recycler_head, parent, false);  
                    return new MyHeaderItemHolder(view, MainActivity.this);  
                case TYPE_NORMAL:  
                    view = inflater.inflate(R.layout.layout_list_item, parent, false);  
                    return new NormalViewHolder(view);  
                case TYPE_EMPTY:  
                    return null;  
                case TYPE_FOOTER:  
                    return null;  
                default:  
                    return null;  
            }  
        }  
  
        @Override  
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {  
            switch (viewHolder.getItemViewType()) {  
                case TYPE_NORMAL:  
                    NormalViewHolder normalViewHolder = (NormalViewHolder) viewHolder;  
                    normalViewHolder.setContent(itemInfos.get(i).model, i);  
                    break;  
                case TYPE_HEADER:  
                    MyHeaderItemHolder headerViewHolder = (MyHeaderItemHolder) viewHolder;  
                    headerViewHolder.setContent();  
                    break;  
                case TYPE_FOOTER:  
                case TYPE_EMPTY:  
                    break;  
                default:  
                    break;  
            }  
        }  
  
        @Override  
        public int getItemCount() {  
            return itemInfos.size();  
        }  
  
        private class EmptyItemHolder extends RecyclerView.ViewHolder {  
            public EmptyItemHolder(View itemView) {  
                super(itemView);  
            }  
        }  
  
        private class MyHeaderItemHolder extends RecyclerView.ViewHolder {  
            private Context context;  
            private ImageView imageView;  
  
            public MyHeaderItemHolder(View itemView, Context context) {  
                super(itemView);  
                this.context = context;  
                imageView = (ImageView) itemView.findViewById(R.id.img_main_recycler_head_banner);  
                imageView.post(new Runnable() {  
                    @Override  
                    public void run() {  
                        anchorHeight = imageView.getMeasuredHeight() - layoutToolBarBackground.getMeasuredHeight();  
                    }  
                });  
            }  
  
            //填充头部内容  
            public void setContent() {  
  
            }  
        }  
  
        private class NormalViewHolder extends RecyclerView.ViewHolder {  
            private Model model;  
            private TextView nameView;  
            private TextView descView;  
  
            public NormalViewHolder(View itemView) {  
                super(itemView);  
                nameView = (TextView) itemView.findViewById(R.id.text_list_item_name);  
                descView = (TextView) itemView.findViewById(R.id.text_list_item_desc);  
                itemView.setOnClickListener(new OnItemClickListener());  
            }  
  
            public void setContent(Model model, int index) {  
                this.model = model;  
                nameView.setText(model.getName());  
                descView.setText(model.getDesc());  
                itemIndex = index;  
  
            }  
  
            private class OnItemClickListener implements View.OnClickListener {  
                @Override  
                public void onClick(View v) {  
  
                }  
            }  
        }  
  
        private class FooterViewHolder extends RecyclerView.ViewHolder {  
  
            public FooterViewHolder(View itemView) {  
                super(itemView);  
            }  
        }  
    }  
  
}  

ok,到这里demo就搞定了!当然如果你的标题栏上的文字太长的话,你也可以自己给textView加上跑马灯效果,很简单,不知道的人可以自行去谷歌百度,记得给textView加上焦点就可以了。项目地址:点击打开链接

我的微信公共账号,欢迎关注
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容