Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android高仿微信底部漸變導航欄

android高仿微信底部漸變導航欄

編輯:關於Android編程

最近有很多人微信底部的變色卡片導航是怎麼做的,我在網上看了好幾個例子,都是效果接近,都存有一些差異,自己琢磨也做了一個,幾乎99%的還原,效果還不錯吧

\

仔細觀察微信圖片,發現他有兩部分內容,外面的邊框和裡面的內容,內容的顏色由綠變為透明,這部分可以直接改變透明度,外面的邊框,顏色在灰色和綠色之間變化,就不能簡單的改變透明度了,ImageView的tint 為我們提供了可行方案,tint可以為圖標著色,既可以在xml中,也可以在代碼中設置,一共有16種模式,分別為

\

在xml中設置:直接添加tint屬性,選擇tintMode模式

 

 

在java代碼中設置

 

 

mGreenImageView.setColorFilter(color,mode) mode參數類型  PorterDuff.Mode
為了理解不同顏色,不同透明度的圖片在設置不同的tint模式,不同的顏色後的變化,寫了一個demo,四個滑動條分別代表了顏色的alpha,R、G、B值,改變滑動為止,通過Color.argb(alpha,red,green,blue)動態組合出不同的顏色,通過Spinner選擇不同的模式,通過給圖像設置模式和不同的tint顏色,展示不同的效果,觀察結果,可以知道給imageview設置tint後,圖標最後展示出來的顏色不僅和設置的模式相關,還和圖像的原有顏色和透明度相關。具體是怎樣的相關性,語言描述不清,請自行體會。

 

\

 

選了實心綠,透明白,實心紫紅的三張圖片進行測試驗證

\\\

\\\

界面很簡單,只是一些基本的控件,代碼如下

 

public class SimpleActivity extends Activity {
    private ImageView mGreenImageView;
    private ImageView mTransparentImageView;
    private ImageView mRedImageView;
    //透明度滑動條
    private SeekBar mTransparentSeekBar;
    private Spinner mSpinner;
    //紅色滑動條
    private SeekBar mRedSeekBar;
    //綠色滑動條
    private SeekBar mGreenSeekBar;
    //藍色滑動條
    private SeekBar mBlueSeekBar;
    private TextView mTextView;
    private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener; //滑動條監聽器
    //PorterDuff.Mode 列表
    private static final PorterDuff.Mode[] MODES = new PorterDuff.Mode[]{
            PorterDuff.Mode.ADD,
            PorterDuff.Mode.CLEAR,
            PorterDuff.Mode.DARKEN,
            PorterDuff.Mode.DST,
            PorterDuff.Mode.DST_ATOP,
            PorterDuff.Mode.DST_IN,
            PorterDuff.Mode.DST_OUT,
            PorterDuff.Mode.DST_OVER,
            PorterDuff.Mode.LIGHTEN,
            PorterDuff.Mode.MULTIPLY,
            PorterDuff.Mode.OVERLAY,
            PorterDuff.Mode.SCREEN,
            PorterDuff.Mode.SRC,
            PorterDuff.Mode.SRC_ATOP,
            PorterDuff.Mode.SRC_IN,
            PorterDuff.Mode.SRC_OUT,
            PorterDuff.Mode.SRC_OVER,
            PorterDuff.Mode.XOR
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);
        mGreenImageView = (ImageView) findViewById(R.id.green);
        mTransparentImageView= (ImageView) findViewById(R.id.transparent);
        mRedImageView= (ImageView) findViewById(R.id.red);
        mTextView= (TextView) findViewById(R.id.text);
        mTransparentSeekBar = (SeekBar) findViewById(R.id.alpha_seekbar);
        mRedSeekBar= (SeekBar) findViewById(R.id.red_seekbar);
        mGreenSeekBar= (SeekBar) findViewById(R.id.green_seekbar);
        mBlueSeekBar= (SeekBar) findViewById(R.id.blue_seekbar);
        mSpinner= (Spinner) findViewById(R.id.spinner);
        SpinnerAdapter spinnerAdapter=ArrayAdapter.createFromResource(SimpleActivity.this,R.array.blend_modes, android.R.layout.simple_list_item_1);
        mSpinner.setAdapter(spinnerAdapter);
        initListener();


    }

    private void initListener() {
        mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView parent, View view, int position, long id) {
                updateImage(getRGBColor(),getMode());
            }

            @Override
            public void onNothingSelected(AdapterView parent) {

            }
        });
        mOnSeekBarChangeListener=new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                updateImage(getRGBColor(),getMode());
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        };
        mTransparentSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
        mRedSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
        mGreenSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
        mBlueSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
    }

    private PorterDuff.Mode getMode() {
        return MODES[mSpinner.getSelectedItemPosition()];
    }

    /**
     * @return 根據ARGB顏色滑動條的數值計算顏色值
     */
    private int getRGBColor() {
        int alpha= mTransparentSeekBar.getProgress();
        int red=mRedSeekBar.getProgress();
        int green=mGreenSeekBar.getProgress();
        int blue=mBlueSeekBar.getProgress();
        return Color.argb(alpha,red,green,blue);
    }

    /**
     * 更新顏色 模式
     * @param color
     * @param mode
     */
    private void updateImage(int color,  PorterDuff.Mode mode ) {
        mGreenImageView.setColorFilter(color,mode);
        mTransparentImageView.setColorFilter(color,mode);
        mRedImageView.setColorFilter(color,mode);
        mTextView.setTextColor(color);
    }
}
通過這個例子,可以看到在src_in模式下,如果給圖標設置了tint,即著色後,圖標顯現的顏色和原有顏色無關,只和原來圖像的透明度有關,圖像越透明,著色越淡,圖像實,著色越深

 

 

\

 

現在已經介紹了ImageView中tint使用的基礎知識,下面我們就開始我們標題中所說的微信導航欄效果,我用肉眼能識別精度仔細觀察了微信,發現微信主要有兩個部分,外面的框和裡面的內容,從上一頁滑到下一頁,滑動到一半前,上一頁的外框保持不變,內容由綠色變為透明,下一頁的外框由灰色變為綠色,滑到一半後,上一頁的外框由綠色變為灰色,下一頁的內容由透明變為綠色,現象已經描述的很清楚了,現在我們用兩張圖片實現效果,一張邊框,一張內容,使用tint 的src_in模式,可以把任意純色圖片喜歡的顏色,為了方便,內容只改變透明度,選為綠色,邊框任意,監聽ViewPager滑動狀態,根據ViewPager便宜量,計算當前顏色值,tint著色渲染

布局文件

 


<framelayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="horizontal" tools:context="com.why.drawabletinttest.PagerActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    
    
        
            <framelayout android:gravity="center_horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content">
                
                
                
            </framelayout>
            
        

        
            <framelayout android:gravity="center_horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content">
                
                
                

            </framelayout>
            

        

        
            <framelayout android:gravity="center_horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content">
                

                />
                
                

            </framelayout>
            
        
    

</framelayout>

\

Activity代碼

 

package com.why.drawabletinttest;

import android.app.Activity;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * @author wanghuayan
 */
public class PagerActivity extends Activity {
    private ViewPager mViewPager;
    //灰色以及相對應的RGB值
    private int mGrayColor;
    private int mGrayRed;
    private int mGrayGreen;
    private int mGrayBlue;
    //灰色以及相對應的RGB值
    private int mGreenColor;
    private int mGreenRed;
    private int mGreenGreen;
    private int mGreenBlue;
    private List textViews;//viewpager中適配的 item
    private ImageView[] mBorderimageViews;  //外部的邊框
    private ImageView[] mContentImageViews; //內部的內容
    private ImageView[] mWhiteImageViews;  //發現上面的白色部分
    private TextView[] mTitleViews;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pager);
        initColor();
        mViewPager = (ViewPager) findViewById(R.id.pager_view);
        ImageView imageView1 = (ImageView) findViewById(R.id.image1);
        ImageView imageView2 = (ImageView) findViewById(R.id.image2);
        ImageView imageView3 = (ImageView) findViewById(R.id.image3);
        mBorderimageViews = new ImageView[]{imageView1, imageView2, imageView3};
        TextView textView = new TextView(PagerActivity.this);
        TextView textView1 = new TextView(PagerActivity.this);
        TextView textView2 = new TextView(PagerActivity.this);
        textViews = new ArrayList<>();
        textViews.add(textView);
        textViews.add(textView1);
        textViews.add(textView2);

        ImageView topImageView1 = (ImageView) findViewById(R.id.image1_top);
        ImageView topImageView2 = (ImageView) findViewById(R.id.image2_top);
        ImageView topImageView3 = (ImageView) findViewById(R.id.image3_top);
        mContentImageViews = new ImageView[]{topImageView1, topImageView2, topImageView3};


        ImageView whiteImageView1 = (ImageView) findViewById(R.id.image1_white);
        ImageView whiteImageView2 = (ImageView) findViewById(R.id.image2_white);
        ImageView whiteImageView3 = (ImageView) findViewById(R.id.image3_white);
        mWhiteImageViews = new ImageView[]{whiteImageView1, whiteImageView2, whiteImageView3};


        TextView titileView1 = (TextView) findViewById(R.id.text1);
        TextView titileView2 = (TextView) findViewById(R.id.text2);
        TextView titileView3 = (TextView) findViewById(R.id.text3);
        mTitleViews = new TextView[]{titileView1, titileView2, titileView3};


        ItemPagerAdapter adapter = new ItemPagerAdapter(textViews);
        mViewPager.setAdapter(adapter);
        setSelection(0);


        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                if (positionOffset > 0) {
                    if (positionOffset < 0.5) {
                        //  滑動到一半前,上一頁的邊框保持綠色不變,下一頁的邊框由灰色變為綠色
                        mBorderimageViews[position].setColorFilter(mGreenColor, PorterDuff.Mode.SRC_IN);
                        mBorderimageViews[position + 1].setColorFilter(getGrayToGreen(positionOffset), PorterDuff.Mode.SRC_IN);
                        //   上一頁的內容保持由實心變為透明,下一頁的內容保持透明
                        mContentImageViews[position].setAlpha((1 - 2 * positionOffset));
                        mContentImageViews[position + 1].setAlpha(0f);
                        //文字顏色變化
                        mTitleViews[position].setTextColor(mGreenColor);
                        mTitleViews[position + 1].setTextColor(getGrayToGreen(positionOffset));

                    } else {
                        //滑動到一半後,上一頁的邊框由綠變為灰色,,下一頁邊框保持綠色不變
                        mBorderimageViews[position].setColorFilter(getGreenToGray(positionOffset), PorterDuff.Mode.SRC_IN);
                        mBorderimageViews[position + 1].setColorFilter(mGreenColor, PorterDuff.Mode.SRC_IN);
                        //上一頁的內容保持透明,下一頁的內容由透明變為實心綠色
                        mContentImageViews[position].setAlpha(0f);
                        mContentImageViews[position + 1].setAlpha(2 * positionOffset - 1);
                        mTitleViews[position].setTextColor(getGreenToGray(positionOffset));
                        mTitleViews[position + 1].setTextColor(mGreenColor);
                        if (position > 0.8) {
                            mWhiteImageViews[position + 1].setVisibility(View.VISIBLE);
                            mWhiteImageViews[position + 1].setAlpha(10 * positionOffset - 8);
                        } else {
                            mWhiteImageViews[position + 1].setVisibility(View.GONE);
                        }
                    }
                }


            }

            @Override
            public void onPageSelected(int position) {
                setSelection(position);

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });


    }

    /**
     * 設置索引  當前導航頁邊框綠色,內容實心綠,其他頁邊框灰色,內容透明
     *
     * @param position
     */
    private void setSelection(int position) {
        for (int i = 0; i < mBorderimageViews.length; i++) {
            if (i == position) {
                mBorderimageViews[i].setColorFilter(mGreenColor, PorterDuff.Mode.SRC_IN);
                mContentImageViews[i].setAlpha(1f);
                mWhiteImageViews[i].setVisibility(View.VISIBLE);
                mTitleViews[i].setTextColor(mGreenColor);
            } else {
                mBorderimageViews[i].setColorFilter(mGrayColor, PorterDuff.Mode.SRC_IN);
                mContentImageViews[i].setAlpha(0f);
                mWhiteImageViews[i].setVisibility(View.GONE);
                mTitleViews[i].setTextColor(mGrayColor);
            }
        }
    }


    private void initColor() {
        mGrayColor = getResources().getColor(R.color.gray);
        mGrayRed = Color.red(mGrayColor);
        mGrayGreen = Color.green(mGrayColor);
        mGrayBlue = Color.blue(mGrayColor);
        mGreenColor = getResources().getColor(R.color.green);
        mGreenRed = Color.red(mGreenColor);
        mGreenGreen = Color.green(mGreenColor);
        mGreenBlue = Color.blue(mGreenColor);
    }

    /**
     * 偏移量在 0——0.5區間 ,左邊一項顏色不變,右邊一項顏色從灰色變為綠色,根據兩點式算出RGB變化函數,組合出顏色
     *
     * @param positionOffset
     * @return
     */
    private int getGrayToGreen(float positionOffset) {
        int red = (int) (positionOffset * (mGreenRed - mGrayRed) * 2 + mGrayRed);
        int green = (int) (positionOffset * (mGreenGreen - mGrayGreen) * 2 + mGrayGreen);
        int blue = (int) ((positionOffset) * (mGreenBlue - mGrayBlue) * 2 + mGrayBlue);
        Log.d("why ", "#### " + red + "  " + green + "  " + blue);
        return Color.argb(255, red, green, blue);
    }

    /**
     * 偏移量在 0.5--1 區間,顏色從綠色變成灰色,根據兩點式算出變化RGB隨偏移量變化函數,組合出顏色
     *
     * @param positionOffset
     * @return
     */
    private int getGreenToGray(float positionOffset) {
        int red = (int) (positionOffset * (mGrayRed - mGreenRed) * 2 + 2 * mGreenRed - mGrayRed);
        int green = (int) (positionOffset * (mGrayGreen - mGreenGreen) * 2 + 2 * mGreenGreen - mGrayGreen);
        int blue = (int) (positionOffset * (mGrayBlue - mGreenBlue) * 2 + 2 * mGreenBlue - mGrayBlue);
        Log.d("why ", "#### " + red + "  " + green + "  " + blue);
        return Color.argb(255, red, green, blue);
    }


    /**
     * viewpager適配器
     */
    class ItemPagerAdapter extends PagerAdapter {
        List list;

        public ItemPagerAdapter(List views) {
            list = views;
        }

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            return arg0 == arg1;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            switch (position) {
                case 0:
                    list.get(position).setText("晴川歷歷漢陽樹");
                    break;
                case 1:
                    list.get(position).setText("芳草萋萋鹦鹉洲");
                    break;
                case 2:
                    list.get(position).setText("長煙落日孤城閉");
                    break;
            }
            list.get(position).setGravity(Gravity.CENTER);

            container.addView(list.get(position), 0);
            return list.get(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(list.get(position));
        }
    }
}

 

到此為止,微信滑動導航卡就完成了,不需要自定義,用簡單的imageview就可以完成,效果也是非常好,可能有點難度的就是滑動過程中顏色的計算,就是高中的兩點式計算,這裡換個馬甲,有人可能有些迷惑。顏色可以分解為RGB三色,分別算出當前偏移量上的RGB,在組合在一起。舉個例子哇,在0.5到1之間,顏色從 綠色變為灰色,列個函數(color-綠)/(position-0.5)=(灰-綠)/(1-0.5),算出color和 position函數,置換為對應的RGB變化。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved