1. 程式人生 > >android高仿微信佈局(二)

android高仿微信佈局(二)

前言

這期我們講講怎麼實現微信的左右滑動的效果和底部的tabs欄
廢話不多說,開工吧!

首先我們先看看總體佈局是怎麼寫的。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:hyman="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.poulwalker.demobar.AppBarActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="微信" android:textColor="#ffffff" android:textSize="20sp"
/> </android.support.v7.widget.Toolbar> <android.support.v4.view.ViewPager android:id="@+id/id_viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> </android.support.v4.view.ViewPager> <LinearLayout android:layout_width="match_parent" android:layout_height="55dp" android:background="@drawable/tab_bg" android:orientation="horizontal"> <com.example.poulwalker.demobar.ChangeColorIconWithText android:id="@+id/id_indicator_one" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" hyman:icon="@mipmap/ic_weixin" android:padding="5dp" hyman:text="微信" hyman:text_size="12sp" hyman:color="#3F51B5"/> <com.example.poulwalker.demobar.ChangeColorIconWithText android:id="@+id/id_indicator_two" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" hyman:icon="@mipmap/ic_friend" android:padding="5dp" hyman:text="通訊錄" hyman:text_size="12sp" hyman:color="#3F51B5"/> <com.example.poulwalker.demobar.ChangeColorIconWithText android:id="@+id/id_indicator_three" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" hyman:icon="@mipmap/ic_find" android:padding="5dp" hyman:text="發現" hyman:text_size="12sp" hyman:color="#3F51B5"/> <com.example.poulwalker.demobar.ChangeColorIconWithText android:id="@+id/id_indicator_four" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" hyman:icon="@mipmap/ic_me" android:padding="5dp" hyman:text="我" hyman:text_size="12sp" hyman:color="#3F51B5"/> </LinearLayout> </LinearLayout>

關於第一個控制元件toolbar,我們在第一期已經講了。不懂的童鞋可以檢視上期講的內容。

根據佈局我們可以看到有ViewPager、還有ChangeColorIconWithText。其中ChangeColorIconWithText是自己定義的。這個佈局的效果是怎麼樣的呢?諸位開啟自己的手機微信就能看到啦。

接下來我們要在程式碼裡實現微信的左劃右劃和變色的功能。

ChangeColorIconWithText.java的實現

第一步定義。

    private int mColor = 0xFF45C01A;
    private Bitmap mIconBitmap;
    private String mText = "微信";
    private int mTextSize = (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics());

    private Canvas mCanvas;
    private Bitmap mBitmap;
    private Paint mPaint;

    private float mAlpha;

    private Rect mIconRect;
    private Rect mTextBound;
    private Paint mTextPaint;

    public ChangeColorIconWithText(Context context)
    {
        this(context, null);
    }

    public ChangeColorIconWithText(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

第二步獲取自定義屬性的值

/**
     * 獲取自定義屬性的值
     * 
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public ChangeColorIconWithText(Context context, AttributeSet attrs,
                                   int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.ChangeColorIconWithText);

        int n = a.getIndexCount();

        for (int i = 0; i < n; i++)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
            case R.styleable.ChangeColorIconWithText_icon:
                BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);
                mIconBitmap = drawable.getBitmap();
                break;
            case R.styleable.ChangeColorIconWithText_color:
                mColor = a.getColor(attr, 0xFF45C01A);
                break;
            case R.styleable.ChangeColorIconWithText_text:
                mText = a.getString(attr);
                break;
            case R.styleable.ChangeColorIconWithText_text_size:
                mTextSize = (int) a.getDimension(attr, TypedValue
                        .applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,
                                getResources().getDisplayMetrics()));
                break;
            }

        }

        a.recycle();

        mTextBound = new Rect();
        mTextPaint = new Paint();
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setColor(0Xff555555);
        mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);

    }

第三步各函式的定義

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int iconWidth = Math.min(getMeasuredWidth() - getPaddingLeft()
                - getPaddingRight(), getMeasuredHeight() - getPaddingTop()
                - getPaddingBottom() - mTextBound.height());

        int left = getMeasuredWidth() / 2 - iconWidth / 2;
        int top = getMeasuredHeight() / 2 - (mTextBound.height() + iconWidth)
                / 2;
        mIconRect = new Rect(left, top, left + iconWidth, top + iconWidth);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        canvas.drawBitmap(mIconBitmap, null, mIconRect, null);

        int alpha = (int) Math.ceil(255 * mAlpha);

        // 記憶體去準備mBitmap , setAlpha , 純色 ,xfermode , 圖示
        setupTargetBitmap(alpha);
        // 1、繪製原文字 ; 2、繪製變色的文字
        drawSourceText(canvas, alpha);
        drawTargetText(canvas, alpha);

        canvas.drawBitmap(mBitmap, 0, 0, null);

    }

    /**
     * 繪製變色的文字
     * 
     * @param canvas
     * @param alpha
     */
    private void drawTargetText(Canvas canvas, int alpha)
    {
        mTextPaint.setColor(mColor);
        mTextPaint.setAlpha(alpha);
        int x = getMeasuredWidth() / 2 - mTextBound.width() / 2;
        int y = mIconRect.bottom + mTextBound.height();
        canvas.drawText(mText, x, y, mTextPaint);

    }

    /**
     * 繪製原文字
     * 
     * @param canvas
     * @param alpha
     */
    private void drawSourceText(Canvas canvas, int alpha)
    {
        mTextPaint.setColor(0xff333333);
        mTextPaint.setAlpha(255 - alpha);
        int x = getMeasuredWidth() / 2 - mTextBound.width() / 2;
        int y = mIconRect.bottom + mTextBound.height();
        canvas.drawText(mText, x, y, mTextPaint);

    }

    /**
     * 在記憶體中繪製可變色的Icon
     */
    private void setupTargetBitmap(int alpha)
    {
        mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
                Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
        mPaint = new Paint();
        mPaint.setColor(mColor);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setAlpha(alpha);
        mCanvas.drawRect(mIconRect, mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mPaint.setAlpha(255);
        mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint);
    }

    private static final String INSTANCE_STATUS = "instance_status";
    private static final String STATUS_ALPHA = "status_alpha";

    @Override
    protected Parcelable onSaveInstanceState()
    {
        Bundle bundle = new Bundle();
        bundle.putParcelable(INSTANCE_STATUS, super.onSaveInstanceState());
        bundle.putFloat(STATUS_ALPHA, mAlpha);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state)
    {
        if (state instanceof Bundle)
        {
            Bundle bundle = (Bundle) state;
            mAlpha = bundle.getFloat(STATUS_ALPHA);
            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATUS));
            return;
        }
        super.onRestoreInstanceState(state);
    }

    public void setIconAlpha(float alpha)
    {
        this.mAlpha = alpha;
        invalidateView();
    }

    /**
     * 重繪
     */
    private void invalidateView()
    {
        if (Looper.getMainLooper() == Looper.myLooper())
        {
            invalidate();
        } else
        {
            postInvalidate();
        }
    }
TabFragment.java的實現
public class TabFragment extends Fragment
{
    private String mTitle = "Default";

    public static final String TITLE = "title";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState)
    {
        if (getArguments() != null)
        {
            mTitle = getArguments().getString(TITLE);
        }

        TextView tv = new TextView(getActivity());
        tv.setTextSize(20);
        tv.setBackgroundColor(Color.parseColor("#ffffffff"));
        tv.setText(mTitle);
        tv.setGravity(Gravity.CENTER);
        return tv;

    }
}

接下來就是在主活動裡呼叫了

public class AppBarActivity extends AppCompatActivity implements View.OnClickListener,ViewPager.OnPageChangeListener{}

第一步定義變數。

private ViewPager mViewPager;
    private List<Fragment> mTabs = new ArrayList<Fragment>();
    private String[] mTitles = new String[]
            { "First Fragment !", "Second Fragment !","Three Fragment !","four"};
    private FragmentPagerAdapter mAdapter;

    private List<ChangeColorIconWithText> mTabIndicators = new ArrayList<ChangeColorIconWithText>();

第二步,初始化所有事件

    /**
     * 初始化所有事件
     */
    private void initEvent()
    {

        mViewPager.setOnPageChangeListener(this);

    }


    private void initView()
    {
        mViewPager = (ViewPager) findViewById(R.id.id_viewpager);

        ChangeColorIconWithText one = (ChangeColorIconWithText) findViewById(R.id.id_indicator_one);
        mTabIndicators.add(one);
        ChangeColorIconWithText two = (ChangeColorIconWithText) findViewById(R.id.id_indicator_two);
        mTabIndicators.add(two);
        ChangeColorIconWithText three = (ChangeColorIconWithText) findViewById(R.id.id_indicator_three);
        mTabIndicators.add(three);
        ChangeColorIconWithText four = (ChangeColorIconWithText) findViewById(R.id.id_indicator_four);
        mTabIndicators.add(four);

        one.setOnClickListener(this);
        two.setOnClickListener(this);
        three.setOnClickListener(this);
        four.setOnClickListener(this);

        one.setIconAlpha(1.0f);

    }

左劃右劃的實現

private void initDatas()
    {
        for (String title : mTitles)
        {
            TabFragment tabFragment = new TabFragment();
            Bundle bundle = new Bundle();
            bundle.putString(TabFragment.TITLE, title);
            tabFragment.setArguments(bundle);
            mTabs.add(tabFragment);
        }


        mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
        {

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

            @Override
            public Fragment getItem(int position)
            {
                return mTabs.get(position);
            }
        };
    }

點選事件及其餘函式的實現

 @Override
    public void onClick(View v) {
        clickTab(v);

    }

    private void clickTab(View v) {
        resetOtherTabs();

        switch (v.getId())
        {
            case R.id.id_indicator_one:
                mTabIndicators.get(0).setIconAlpha(1.0f);
                mViewPager.setCurrentItem(0, false);
                break;
            case R.id.id_indicator_two:
                mTabIndicators.get(1).setIconAlpha(1.0f);
                mViewPager.setCurrentItem(1, false);
                break;
            case R.id.id_indicator_three:
                mTabIndicators.get(2).setIconAlpha(1.0f);
                mViewPager.setCurrentItem(2, false);
                break;
            case R.id.id_indicator_four:
                mTabIndicators.get(3).setIconAlpha(1.0f);
                mViewPager.setCurrentItem(3, false);
                break;
        }
    }

    private void resetOtherTabs() {
        for (int i = 0; i < mTabIndicators.size(); i++)
        {
            mTabIndicators.get(i).setIconAlpha(0);
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (positionOffset > 0)
        {
            ChangeColorIconWithText left = mTabIndicators.get(position);
            ChangeColorIconWithText right = mTabIndicators.get(position + 1);
            left.setIconAlpha(1 - positionOffset);
            right.setIconAlpha(positionOffset);
        }

    }

    @Override
    public void onPageSelected(int position) {

    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

最後在onCreate方法裡再初始化一遍

        initView();
        initDatas();
        mViewPager.setAdapter(mAdapter);
        initEvent();

授人以魚不如授人以漁,這裡我就不釋出整個工程了,剩下的事情留給大家慢慢去發揮吧!