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加上焦点就可以了。

项目地址:点击打开链接




本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
这一篇,承接地八话。使用高效的方式备份短信——xml序列化器。 存储短信,要以对象的方式存储。首先创建javabean: package com.itydl.createxml.domain;public class Message {private String body;private String date;private String address;private String type;public String getBody() {return body;}public void setB

android独特的天气预报 - 2016-07-24 14:07:50

android独特的天气预报 package com.dchan.myweather;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.security.PublicKey;import java.util.ArrayList;import java.util.Calendar;import java.util.Collection;import java.util.HashMap;impo

cocoapods的安装和使用 总结 - 2016-07-24 14:07:48

一、CocoaPods 是什么? CocoaPods 是开发 OS X 和 iOS 应用程序的一个第三方库的依赖管理工具。利用CocoaPods,可以定义自己的依赖关系 (称作 pods),并且随着时间的变化,以及在整个开发环境中对第三方库的版本管理非常方便。 CocoaPods 背后的理念主要体现在两个方面。首先,在工程中引入第三方代码会涉及到许多内容。针对 Objective-C 初级开发者来说,工程文件的配置会让人很沮丧。在配置buildphases和linker flags过程中,会引起许多人为因
最近有一段时间没写博客了,一方面是工作比较忙,一方面也着实本人水平有限,没有太多能与大家分享的东西,也就是在最近公司要做一个抢红包的功能,老板发话了咋们就开干呗,本人就开始在网上收集资料,经过整理和实践,总算完美实现了功能,这里拿出本人一点微薄的成就与大家分享。 首先界面是这样的 开启自动抢红包只需点击相应的选项即可,下面我们进入正题,实现自动抢红包的原理,其实是借助android下的一个辅助服务AccessibilityService,这个服务是google公司为许多Android使用者因为各种情况导致
在实现该控件之前,先说一下该控件的难度, 一、   每个item中如果有RadioButton之类,可以focus焦点的,点击效果可能会失效   二、无限的滚动   下面是效果图: 实现上图的效果,一共自定义了两个 控件,viewpager+底部导航图标 下面我先来讲解一下,viewpager的实现: 1.初始化 pre name="code" class="java"/** 点击按下的坐标 **/PointF downP = new PointF();/** 当前按下的坐标 **/PointF curP

Android-下拉刷新库 - 2016-07-24 14:07:44

前言 入职接近半个多月,有几天空闲,所以想着能不能自己实现一个库来练练手,因为之前一直想要实现下拉刷新的功能,因此就有了这样一个自制的下拉刷新库——RefreshWidgetLib. 关于下拉刷新 下拉刷新,作为一个几乎每个应用都会出现的一种控件,不言而喻,它对于提高用户体验有着很重要的作用,而且也已经成为了人们习惯的一种操作。说起下拉刷新这种设计,最早的引入者是在2008年上线的Tweetie,Tweetie引入了如今随处可见的“下拉刷新”设计,不仅有多达数百款App Store应用使用这种设计,就连苹

从AIDL看Android跨进程通信 - 2016-07-24 14:07:38

AIDL是Android实现IPC的一种重要的方式,理解它的原理对理解Android进程间通信有很大的帮助。AIDL的定义,已经有很多介绍的文章了,这里就不做详解了。我们直接从实例入手来分析AIDL实现原理。 AIDL的使用 首先需要定义AIDL接口IMyService.aidl: // IMyService.aidl package com.chuck.aidldemo; // Declare any non-default types here with import statements inter
OC与Swift两种实现方式基本上区别不大,主要是在一些对象或方法的调用方式不同 OC代码样式: self.view.backgroundColor = [UIColor blackColor];          //加载颗粒状的火花图片     CAEmitterLayer *emitterLa = [CAEmitterLayer layer];     emitterLa.emitterPosition = CGPointMake(self.view.bounds.size.width/2, sel
前言 相信很多朋友在开发中都会遇到图片上传的情况,尤其是多图上传,最 经典的莫过于微信的图片选择了。所有很多情况下会使用到多图选择。 所以就有了这篇文章,今天抽点时间写了个控件。 支持自定义选择图片的样式 支持设置图片选择数量 支持图片预览,删除 支持图片拍照 先来看看效果 实现分析 假如不定义控件,我们要实现这样一个功能,无非是写个GridView在item点击的时候去显示图片进行选择,在返回界面的时候进行GridView的数据刷新。我们把这些逻辑写在我们自定义的GridView中,就成了一个新的控件。
在360对DroidPlugin的特点介绍中有云: 插件的四大组件完全不需要在Host程序中注册,支持Service、Activity、BroadcastReceiver、ContentProvider四大组件。 实现了进程管理,插件的空进程会被及时回收,占用内存低。 之所以支持Service,Activity,ContentProvider三大组件,是因为DroidPlugin在AndroidManifest文件中预先注册了8个运行插件的进程,每个进程预注册Service一个, ContentProvi