Android漸變標題欄的實現

Android4.4以上推出了Toolbar,改變程序的style屬性就可以給手機的標題欄填充顏色洼冻,可以是你設置好的系統(tǒng)的主題色蓝厌,也可以是自己填充的顏色诞帐,其實這個效果在iOS早就有了,但在Android中還是很少見的祸穷。在iOS中性穿,最常見的Navigationbar的效果就是一個轉場動畫(多出現于兩個界面切換的時候),一個就是隨著手勢滑動背景漸變(多出現于詳情頁)雷滚。今天我們就來實現下大多出現于詳情頁的這個漸變效果的標題欄需曾。
具體效果見:點擊打開鏈接

接下來我們就來實現這個效果。
首先祈远,我們要先把手機上面的狀態(tài)欄的顏色背景隱藏掉呆万,在這里會有一個坑,在小米和魅族手機里车份,好想說是MIUI6以上谋减,上面狀態(tài)欄上的時間啊什么的文字默認的顏色是白色,如果你的Toolbar的背景是相對深顏色的話扫沼,是沒有問題的出爹,但是如果你的Toolbar是相對淺的背景顏色庄吼,那么很可能這些時間文字會顯示不出來,那么就要修改上面狀態(tài)欄的顏色了严就。具體可以參考這篇:點擊打開鏈接
先在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>  

接下來我們就要把狀態(tài)欄設置為透明:

private void setTranslucentWindows(Activity activity) {  
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {  
            //透明狀態(tài)欄  
            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來代替了輪播圖衰倦。為了達到漸變的效果袒炉,我們要去監(jiān)聽滑動事件,是否滑動到imageView的高度樊零,也就是把imageView隱藏我磁,當正好隱藏的時候標題欄的文字將出現(這個一般看交互,如果大圖下面有標題驻襟,一般建議標題覆蓋以后夺艰,標題欄上的標題再顯示),當前的y與整體要滑動距離的百分比來控制標題欄的背景透明度沉衣。在這里要注意郁副,當onCreate方法的時候,一個view的getMeasuredHeight()方法或者寬度的方法獲得的都是0豌习,因為這個時候你的view還沒有draw上去存谎,只有當onCreate方法執(zhí)行完了以后,控件才會被onMeasure肥隆。所以有兩種策略既荚,一種是我以下代碼實現的,等view的onMeasure好了以后再去調用方法栋艳,還有一種是去注冊一個ViewTreeObserver的監(jiān)聽回調恰聘,具體大家可以去自行百度。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) {  
            //透明狀態(tài)欄  
            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閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件势似,死亡現場離奇詭異,居然都是意外死亡僧著,警方通過查閱死者的電腦和手機履因,發(fā)現死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盹愚,“玉大人栅迄,你說我怎么就攤上這事〗耘拢” “怎么了毅舆?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長愈腾。 經常有香客問我憋活,道長,這世上最難降的妖魔是什么虱黄? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任悦即,我火速辦了婚禮,結果婚禮上橱乱,老公的妹妹穿的比我還像新娘辜梳。我一直安慰自己,他們只是感情好仅醇,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布冗美。 她就那樣靜靜地躺著,像睡著了一般析二。 火紅的嫁衣襯著肌膚如雪粉洼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天叶摄,我揣著相機與錄音属韧,去河邊找鬼。 笑死蛤吓,一個胖子當著我的面吹牛宵喂,可吹牛的內容都是我干的。 我是一名探鬼主播会傲,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锅棕,長吁一口氣:“原來是場噩夢啊……” “哼拙泽!你這毒婦竟也來了?” 一聲冷哼從身側響起裸燎,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤顾瞻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后德绿,有當地人在樹林里發(fā)現了一具尸體荷荤,經...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年移稳,在試婚紗的時候發(fā)現自己被綠了蕴纳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡个粱,死狀恐怖古毛,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情几蜻,我是刑警寧澤喇潘,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布体斩,位于F島的核電站梭稚,受9級特大地震影響,放射性物質發(fā)生泄漏絮吵。R本人自食惡果不足惜弧烤,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蹬敲。 院中可真熱鬧暇昂,春花似錦、人聲如沸伴嗡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘪校。三九已至澄暮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阱扬,已是汗流浹背泣懊。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留麻惶,地道東北人馍刮。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像窃蹋,于是被迫代替她去往敵國和親卡啰。 傳聞我的和親對象是個殘疾皇子静稻,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內容