高仿微信6.0界面

前面一篇文章里面,我们谈及到了微信5.2.1,并对其进行了简单的实现。但存在了两个问题:
1.在onPageScrolled()函数中写了很多判断,如果仔细观察,其实不用写的那么复杂。
2.底边文字和图片滑动页面时候,如何跟进滑动过程完成颜色的渐变。
这次我们来进行一一解答,本篇博客主要解决了三个问题:
1.使用ActionBar高仿微信顶部菜单。
2.自定义控件,使用setXfermode完成底部菜单拖动的过程中,完成文字和图片等渐变效果。
3.简化onPageScrolled()方法。
效果如下:

高仿微信6.0界面_第1张图片
D471CAD6-87E9-43E5-A868-E5D42503A832.png

以下为相关代码:

menu_main.xml

 

       

    

   

     

   


上面为menu的相关布局,第一个item为点击搜索,后面四个item为点击加号展现的菜单。
以下为主界面MainActivity的activity_main.xml布局:

    

    

         
            
               
                  
         
    

整个为一个线性布局,上面是一个ViewPager,下面是自定义的四个view,即我们底部的四个tab,关于四个tab我们自定义了四个属性:tab_color,tab_icon,tab_text,text_size。

下面是关于自定义属性的attr.xml文件:


  
    
     
    
   

      
           
          
         
         
  

下面就来到了我们的核心代码部分,第一部分为MainActivity.java:

package com.imooc.weixin;import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends FragmentActivity implements View.OnClickListener, ViewPager.OnPageChangeListener {  
   private ViewPager mViewPager; //初始化ViewPager
   private List mTabs = new ArrayList<>();//Fragment集合 
   private String[] mTitles = new String[]{    
        "First Fragment!", "Second Fragment!", 
        "Third Fragment!", "Fourth Fragment!"    };  //4个tab点击或者滑动对应的Fragment中的text  
   private FragmentPagerAdapter mAdapter; //适配器
   private List mTabsIndictor=new ArrayList<>();//tab集

    @Override 
   protected void onCreate(Bundle savedInstanceState) {   
       super.onCreate(savedInstanceState);  
       setContentView(R.layout.activity_main); 
      /*** 
             右侧加号在部分机器上不会显示,所以这里反射,强制
             让其显示
       ***/
       setOverflowButtonAlways(); 
       if (null != getActionBar()) { 
        /***  隐藏最右侧默认的三个点的图标  ***/  
         getActionBar().setDisplayShowHomeEnabled(false);
        }      
      /***  初始化view  ***/   
      initView();
      /***  初始化数据  ***/     
      initDatas();  
      mViewPager.setAdapter(mAdapter);
     /***  初始化触摸事件  ***/   
     initEvent();   
 }  

  private void initEvent() { 
           mViewPager.addOnPageChangeListener(this); 
   }    

 /***  跟进Tab数量出事后TabFragement  ***/
   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 Fragment getItem(int i) {     
           return mTabs.get(i);  
          }     
  
         @Override 
           public int getCount() { 
               return mTabs.size();  
          }    
    }; 
   }    

/*** 初始化了四个ChangeColorIconWithText  四个tab我们默认显示第一个  所以将第一个tab的alpha设置了为1.0f 其他的tab为0.0f 则默认显示原色  即不是选中状态 ***/
  private void initView() {
        mViewPager = (ViewPager) findViewById(R.id.id_viewpager);  
        ChangeColorIconWithText id_indicator_one = (ChangeColorIconWithText) this.findViewById(R.id.id_indicator_one); 
        ChangeColorIconWithText id_indicator_two = (ChangeColorIconWithText) this.findViewById(R.id.id_indicator_two);   
        ChangeColorIconWithText id_indicator_three = (ChangeColorIconWithText) this.findViewById(R.id.id_indicator_three);  
        ChangeColorIconWithText id_indicator_four = (ChangeColorIconWithText) this.findViewById(R.id.id_indicator_four); 
        mTabsIndictor.add(id_indicator_one); 
        mTabsIndictor.add(id_indicator_two);   
        mTabsIndictor.add(id_indicator_three);  
        mTabsIndictor.add(id_indicator_four);   
        id_indicator_one.setOnClickListener(this); 
        id_indicator_two.setOnClickListener(this);  
        id_indicator_three.setOnClickListener(this);  
        id_indicator_four.setOnClickListener(this);  
        id_indicator_one.setIconAlpha(1.0F);   
 }    

@Override 
   public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);    
    return true;   
 }  

/*** 设置显示加号 ***/ 
 private void setOverflowButtonAlways() { 
       try {           
          ViewConfiguration config = ViewConfiguration.get(this);  
          Field menuKey = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
           menuKey.setAccessible(true); 
           menuKey.setBoolean(config, false);  
      } catch (Exception e) {  
          e.printStackTrace(); 
       }   
 }   

/*** 显示菜单前面的icon ***/
 @Override 
   public boolean onMenuOpened(int featureId, Menu menu) { 
       if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
            if (menu.getClass().getSimpleName().equals("MenuBuilder")) { 
               try {            
                 Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                 m.setAccessible(true);   
                 m.invoke(menu, true);    
            } catch (Exception e) {  
                  e.printStackTrace();   
             }         
       }    
    }  
      return super.onMenuOpened(featureId, menu);  
  }  

  @Override 
   public void onClick(View v) { 
       /*** 每次点击tab  重置tab状态 ***/
      resetOtherTabs();   
      switch (v.getId())   
      {      
         case R.id.id_indicator_one: 
               /*** 改变tab选中颜色 ***/
               mTabsIndictor.get(0).setIconAlpha(1.0f);   
              /*** 点击tab  设置相应的Fragment显示  false为去掉了切换适配器Fragment的动画效果 ***/        
               mViewPager.setCurrentItem(0,false); 
               break;         
         case R.id.id_indicator_two: 
               mTabsIndictor.get(1).setIconAlpha(1.0f);  
               mViewPager.setCurrentItem(1,false);      
               break; 
         case  R.id.id_indicator_three:     
              mTabsIndictor.get(2).setIconAlpha(1.0f);   
              mViewPager.setCurrentItem(2,false);       
              break;  
         case R.id.id_indicator_four:
               mTabsIndictor.get(3).setIconAlpha(1.0f); 
               mViewPager.setCurrentItem(3,false);      
               break;        
} 
   }   

 /***   重置其他的Tab颜色     */  
  private void resetOtherTabs() {    
    for (int i=0;i0)   
           {         
            ChangeColorIconWithText   left=mTabsIndictor.get(position); 
            ChangeColorIconWithText    right=mTabsIndictor.get(position+1);     
           left.setIconAlpha(1-positionOffset);   
           right.setIconAlpha(positionOffset);       
            } 
   } 

   @Override  
  public void onPageSelected(int position) {    
    } 
   @Override   
  public void onPageScrollStateChanged(int state)
   {  
   }
}

下面就是来到了我们的关键部分也就是我们自定义的一个ChangeColorIconWithText,下面我们来看下它:

package com.imooc.weixin;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Looper;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

/** * Author:${luomingjun} 
* 时间:2016/6/22 16:25
 */
public class ChangeColorIconWithText extends View {
    private int mTab_Color = 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        AttributeSet  
* @param defStyleAttr 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_tab_icon: 
               BitmapDrawable bitmapDrawable = (BitmapDrawable) a.getDrawable(attr);        
               mIconBitmap = bitmapDrawable.getBitmap();   
                 break;     
          case R.styleable.ChangeColorIconWithText_text:     
               mText = a.getString(attr);   
               break;       
          case R.styleable.ChangeColorIconWithText_tab_color: 
               mTab_Color = a.getColor(attr, 0xFF45C01A);                    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) { 
      /*** 计算绘制tab区域的大小(icon+text)  ***/
       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) {   
      /***  绘制原色的icon  ***/
      canvas.drawBitmap(mIconBitmap, null, mIconRect, null);  
      int alpha = (int) Math.ceil(255 * mAlpha); 
     /***   在内存中绘制可变色的Icon    ***/   
      setUpTargetBitmap(alpha);    
      /***   绘制原色文本    ***/ 
      drawSourceText(canvas, alpha);
      /***   绘制变色文本    ***/ 
      drawTargetText(canvas, alpha);    
      /***   绘制出客变色的icon    ***/ 
      canvas.drawBitmap(mBitmap, 0, 0, null); 
   }  
  
/**    
 * 绘制变色的文本  
 *     
 * @param canvas  
 * @param alpha 
 */ 
   private void drawTargetText(Canvas canvas, int alpha) {
       mTextPaint.setColor(mTab_Color); 
       mTextPaint.setAlpha(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(), Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);     
        mPaint = new Paint(); 
        mPaint.setColor(mTab_Color);    
        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); 
   }   
 
/**   
  * 绘制原文本   
  *    
  * @param canvas canvas    
  * @param alpha  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);   
 }   

/**     
   * 改变alpha值  并重新绘制 
   */
 public void setIconAlpha(float alpha) {   
     this.mAlpha = alpha;   
     invalidateView(); 
   }   

 /**     
   * 重绘  
   */   
 private void invalidateView() {  
      if (Looper.getMainLooper() == Looper.myLooper()) {   
         //Ui线程     
        invalidate();    
    } else {     
        postInvalidate();
        }  
  }   

/**     
   * 防止Activity回收之后  进去之后tab选中的颜色和fragment不对应  不做以下处理  回收之后  默认会选中第一个  
   */   
 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); 
   }
}

上面有一行代码是:

mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

下面我们具体来了解下,如下为Porter-Duff 效果图:

高仿微信6.0界面_第2张图片
0_13219433774KaR.jpg

很明显,我们采用了PorterDuff.Mode.DST_IN,取绘制两层交集,显示上层:
以下博客为Porter-Duff的详细讲解:
http://blog.csdn.net/t12x3456/article/details/10432935

源码:
http://pan.baidu.com/s/1i4CGT1N

你可能感兴趣的:(高仿微信6.0界面)