Android 위 챗 6.1 tab 표시 줄 아이콘 과 글꼴 색상 그 라 데 이 션 구현

위 챗 아이콘 의 색상 이 그 라 데 이 션 되 는 과정 을 보 셨 을 거 라 고 믿 습 니 다.대단 하 시 죠?위 챗 팀 은 디자인 이 든 개발 자 든 대단한 팀 이 라 고 할 수 밖 에 없다.
오늘 은 위 챗 탭 표시 줄 아이콘 과 글꼴 색상 이 그 라 데 이 션 되 는 과정 을 보 여 드 리 겠 습 니 다.그림 부터 올 려!오늘 gif 동적 그림 을 만 드 는 빠 른 방법 을 배 웠 습 니 다.마침 쓸 만 한 것 이 있어 서 예전 에는 뭔 가 를 쓰 고 싶 었 는데,
동태 도 를 어떻게 만 드 는 지 몰라 서 힘 들 었 는데 이제 야 배 웠 어 요.하하,몰래 즐 기 게 해 주세요.어,위 에 그림 이나 그 려...

자,효과 도 보 았 습 니 다.그러면 저도 긴 말 하지 않 고 바로 주제 에 들 어가 코드 를 보 겠 습 니 다.

[java] view plain copy
package moon.wechat.view; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.Rect; 
import android.util.AttributeSet; 
import android.util.TypedValue; 
import android.view.View; 
/** 
 * Created by moon.zhong on 2015/2/4. 
 */ 
public class TabItem extends View { 
  /*    */ 
  private int mTextSize ; 
  /*       */ 
  private int mTextColorSelect ; 
  /*           */ 
  private int mTextColorNormal; 
  /*           */ 
  private Paint mTextPaintNormal; 
  /*           */ 
  private Paint mTextPaintSelect; 
  /*   item     ,         */ 
  private int mViewHeight, mViewWidth; 
  /*     */ 
  private String mTextValue ; 
  /*       */ 
  private Bitmap mIconNormal; 
  /*       */ 
  private Bitmap mIconSelect; 
  /*        */ 
  private Rect mBoundText; 
  /*         */ 
  private Paint mIconPaintSelect; 
  /*         */ 
  private Paint mIconPaintNormal; 
  public TabItem(Context context) { 
    this(context, null); 
  } 
  public TabItem(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
  } 
  public TabItem(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    initView(); 
    initText(); 
  } 
  /*       */ 
  private void initView() { 
    mBoundText = new Rect(); 
  } 
  /*     ,       */ 
  private void initText() { 
    mTextPaintNormal = new Paint(); 
    mTextPaintNormal.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, getResources().getDisplayMetrics())); 
    mTextPaintNormal.setColor(mTextColorNormal); 
    mTextPaintNormal.setAntiAlias(true); 
    mTextPaintNormal.setAlpha(0xff); 
    mTextPaintSelect = new Paint(); 
    mTextPaintSelect.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, getResources().getDisplayMetrics())); 
    mTextPaintSelect.setColor(mTextColorSelect); 
    mTextPaintSelect.setAntiAlias(true); 
    mTextPaintSelect.setAlpha(0); 
    mIconPaintSelect = new Paint(Paint.ANTI_ALIAS_FLAG) ; 
    mIconPaintSelect.setAlpha(0); 
    mIconPaintNormal = new Paint(Paint.ANTI_ALIAS_FLAG) ; 
    mIconPaintNormal.setAlpha(0xff); 
  } 
  /*       */ 
  private void measureText() { 
    mTextPaintNormal.getTextBounds(mTextValue, 0, mTextValue.length(), mBoundText); 
  } 
  /*          ,         */ 
  @Override 
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
    int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
    int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
    int heightSize = MeasureSpec.getSize(heightMeasureSpec); 
    int width = 0, height = 0; 
    measureText(); 
    int contentWidth = Math.max(mBoundText.width(), mIconNormal.getWidth()); 
    int desiredWidth = getPaddingLeft() + getPaddingRight() + contentWidth; 
    switch (widthMode) { 
      case MeasureSpec.AT_MOST: 
        width = Math.min(widthSize, desiredWidth); 
        break; 
      case MeasureSpec.EXACTLY: 
        width = widthSize; 
        break; 
      case MeasureSpec.UNSPECIFIED: 
        width = desiredWidth; 
        break; 
    } 
    int contentHeight = mBoundText.height() + mIconNormal.getHeight(); 
    int desiredHeight = getPaddingTop() + getPaddingBottom() + contentHeight; 
    switch (heightMode) { 
      case MeasureSpec.AT_MOST: 
        height = Math.min(heightSize, desiredHeight); 
        break; 
      case MeasureSpec.EXACTLY: 
        height = heightSize; 
        break; 
      case MeasureSpec.UNSPECIFIED: 
        height = contentHeight; 
        break; 
    } 
    setMeasuredDimension(width, height); 
    mViewWidth = getMeasuredWidth() ; 
    mViewHeight = getMeasuredHeight() ; 
  } 
  @Override 
  protected void onDraw(Canvas canvas) { 
    drawBitmap(canvas) ; 
    drawText(canvas) ; 
  } 
  /*   ,        ,        */ 
  private void drawBitmap(Canvas canvas) { 
    int left = (mViewWidth - mIconNormal.getWidth())/2 ; 
    int top = (mViewHeight - mIconNormal.getHeight() - mBoundText.height()) /2 ; 
    canvas.drawBitmap(mIconNormal, left, top ,mIconPaintNormal); 
    canvas.drawBitmap(mIconSelect, left, top , mIconPaintSelect); 
  } 
  /*   */ 
  private void drawText(Canvas canvas) { 
    float x = (mViewWidth - mBoundText.width())/2.0f ; 
    float y = (mViewHeight + mIconNormal.getHeight() + mBoundText.height()) /2.0F ; 
    canvas.drawText(mTextValue,x,y, mTextPaintNormal); 
    canvas.drawText(mTextValue,x,y, mTextPaintSelect); 
  } 
  public void setTextSize(int textSize) { 
    this.mTextSize = textSize; 
    mTextPaintNormal.setTextSize(textSize); 
    mTextPaintSelect.setTextSize(textSize); 
  } 
  public void setTextColorSelect(int mTextColorSelect) { 
    this.mTextColorSelect = mTextColorSelect; 
    mTextPaintSelect.setColor(mTextColorSelect); 
    mTextPaintSelect.setAlpha(0); 
  } 
  public void setTextColorNormal(int mTextColorNormal) { 
    this.mTextColorNormal = mTextColorNormal; 
    mTextPaintNormal.setColor(mTextColorNormal); 
    mTextPaintNormal.setAlpha(0xff); 
  } 
  public void setTextValue(String TextValue) { 
    this.mTextValue = TextValue; 
  } 
  public void setIconText(int[] iconSelId,String TextValue) { 
    this.mIconSelect = BitmapFactory.decodeResource(getResources(), iconSelId[0]); 
    this.mIconNormal = BitmapFactory.decodeResource(getResources(), iconSelId[1]); 
    this.mTextValue = TextValue; 
  } 
  /*   alpha             ,         */ 
  public void setTabAlpha(float alpha){ 
    int paintAlpha = (int)(alpha*255) ; 
    mIconPaintSelect.setAlpha(paintAlpha); 
    mIconPaintNormal.setAlpha(255-paintAlpha); 
    mTextPaintSelect.setAlpha(paintAlpha); 
    mTextPaintNormal.setAlpha(255-paintAlpha); 
    invalidate(); 
  } 
} 
분석:상기 코드 는 tab 의 모든 아 이 템 의 내용 을 실현 합 니 다.위 챗 의 항목 에서 하나의 아이콘 에 글꼴 을 추가 하 는 것 입 니 다.
핵심 코드 는 Public void setTabAlpha(float alpha)라 는 방법 입 니 다.이 방법 은 viewPager 가 item 을 전환 할 때 오프셋 을 계속 바 꾸 어 호출 하여 계속 바 꾸 는 것 입 니 다.
모든 화필 의 투명 도 는 아이콘 과 색상 의 그 라 데 이 션 을 실현 합 니 다.쉽 죠?여기까지 사실 우리 의 색깔 이 점차 변 하 는 코드 는 이미 실현 되 었 다.다음 내용 은 무시 할 수 있다.
이렇게 하면 우 리 는 MainActivity 의 xml 에서 선형 구 조 를 정의 한 다음 에 네 개의 사용자 정의 View 를 넣 으 면 됩 니 다.근 데 이 정도 면 만족 하 세 요?
제 가 먼저 메 인 액 티 비 티 코드 를 보 여 드 리 겠 습 니 다.

[java] view plain copy
package moon.wechat; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentPagerAdapter; 
import android.support.v4.view.ViewPager; 
import android.support.v7.app.ActionBarActivity; 
import android.os.Bundle; 
import java.util.HashMap; 
import java.util.Map; 
import moon.wechat.view.TabView; 
public class MainActivity extends ActionBarActivity { 
  private String[] mTitle = {"  ", "   ", "  ", " "}; 
  private int[] mIconSelect = {R.drawable.al_, R.drawable.al8, R.drawable.alb, R.drawable.ald}; 
  private int[] mIconNormal = {R.drawable.ala, R.drawable.al9, R.drawable.alc, R.drawable.ale}; 
  private ViewPager mViewPager ; 
  private TabView mTabView ; 
  private Map<Integer,Fragment> mFragmentMap ; 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    mFragmentMap = new HashMap<>() ; 
    mViewPager = (ViewPager)findViewById(R.id.id_view_pager) ; 
    mViewPager.setOffscreenPageLimit(4); 
    mViewPager.setAdapter(new PageAdapter(getSupportFragmentManager())); 
    mTabView = (TabView)findViewById(R.id.id_tab) ; 
    mTabView.setViewPager(mViewPager); 
  } 
  private Fragment getFragment(int position){ 
    Fragment fragment = mFragmentMap.get(position) ; 
    if(fragment == null){ 
      switch (position){ 
        case 0: 
          fragment = new WeChatFragment() ; 
          break ; 
        case 1: 
          fragment = new WeContactFragment(); 
          break ; 
        case 2: 
          fragment = new WeDiscoverFragment(); 
          break; 
        case 3: 
          fragment = new GameFragment() ; 
//          fragment = new WeMineFragment(); 
          break; 
      } 
      mFragmentMap.put(position,fragment) ; 
    } 
    return fragment ; 
  } 
  class PageAdapter extends FragmentPagerAdapter implements TabView.OnItemIconTextSelectListener{ 
    public PageAdapter(FragmentManager fm) { 
      super(fm); 
    } 
    @Override 
    public Fragment getItem(int position) { 
      return getFragment(position); 
    } 
    @Override 
    public int[] onIconSelect(int position) { 
      int icon[] = new int[2] ; 
      icon[0] = mIconSelect[position] ; 
      icon[1] = mIconNormal[position] ; 
      return icon; 
    } 
    @Override 
    public String onTextSelect(int position) { 
      return mTitle[position]; 
    } 
    @Override 
    public int getCount() { 
      return mTitle.length; 
    } 
  } 
} 
간단 하지 않 습 니까?xml 가 더 간단 합 니 다.

[html] view plain copy
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:zgy="http://schemas.android.com/apk/res-auto" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:background="@android:color/white" 
  android:orientation="vertical"> 
  <android.support.v4.view.ViewPager 
    android:id="@+id/id_view_pager" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    > 
    </android.support.v4.view.ViewPager> 
  <moon.wechat.view.TabView 
    android:id="@+id/id_tab" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal" 
    android:background="#eeeeee" 
    zgy:text_size="12sp" 
    zgy:text_normal_color="#ff777777" 
    zgy:text_select_color="#ff45c01a" 
    zgy:item_padding="7dp"> 
   </moon.wechat.view.TabView> 
</LinearLayout> 
우리 가 방금 사용자 정의 한 Tab Item 을 정의 하지 않 고 사용 한 TabView 를 볼 수 있 습 니 다.TabView 는 도대체 무엇 입 니까?다 들 생각 하 실 거 라 고 믿 습 니 다.TabView 는 사실 저희 가 정의 한 선형 레이아웃 입 니 다.

[java] view plain copy
package moon.wechat.view; 
import android.content.Context; 
import android.content.res.TypedArray; 
import android.support.v4.view.PagerAdapter; 
import android.support.v4.view.ViewPager; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.util.TypedValue; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.LinearLayout; 
import java.util.ArrayList; 
import java.util.List; 
import moon.wechat.R; 
/** 
 * Created by moon.zhong on 2015/2/4. 
 */ 
public class TabView extends LinearLayout implements View.OnClickListener { 
  private ViewPager mViewPager; 
  private ViewPager.OnPageChangeListener mOnPageChangeListener; 
  private PagerAdapter mPagerAdapter; 
  private int mChildSize; 
  private List<TabItem> mTabItems; 
  private OnItemIconTextSelectListener mListener; 
  private int mTextSize = 12; 
  private int mTextColorSelect = 0xff45c01a; 
  private int mTextColorNormal = 0xff777777; 
  private int mPadding = 10; 
  public TabView(Context context) { 
    this(context, null); 
  } 
  public TabView(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
  } 
  public TabView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.TabView); 
    int N = typedArray.getIndexCount(); 
    for (int i = 0; i < N; i++) { 
      switch (typedArray.getIndex(i)) { 
        case R.styleable.TabView_text_size: 
          mTextSize = (int) typedArray.getDimension(i, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 
              mTextSize, getResources().getDisplayMetrics())); 
          break; 
        case R.styleable.TabView_text_normal_color: 
          mTextColorNormal = typedArray.getColor(i, mTextColorNormal); 
          break; 
        case R.styleable.TabView_text_select_color: 
          mTextColorSelect = typedArray.getColor(i, mTextColorSelect); 
          break; 
        case R.styleable.TabView_item_padding: 
          mPadding = (int) typedArray.getDimension(i, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 
              mPadding, getResources().getDisplayMetrics())); 
          break; 
      } 
    } 
    typedArray.recycle(); 
    mTabItems = new ArrayList<>(); 
  } 
  public void setViewPager(final ViewPager mViewPager) { 
    if (mViewPager == null) { 
      return; 
    } 
    this.mViewPager = mViewPager; 
    this.mPagerAdapter = mViewPager.getAdapter(); 
    if (this.mPagerAdapter == null) { 
      throw new RuntimeException(" ,    TabView ViewPager ,    ViewPager PagerAdapter"); 
    } 
    this.mChildSize = this.mPagerAdapter.getCount(); 
    this.mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
      @Override 
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
//        Log.v("zgy","=============position="+position+",====positionOffset="+positionOffset) ; 
        View leftView; 
        View rightView; 
        if (positionOffset > 0) { 
          leftView = mViewPager.getChildAt(position); 
          rightView = mViewPager.getChildAt(position + 1); 
          leftView.setAlpha(1 - positionOffset); 
          rightView.setAlpha(positionOffset); 
          mTabItems.get(position).setTabAlpha(1 - positionOffset); 
          mTabItems.get(position + 1).setTabAlpha(positionOffset); 
        } else { 
          mViewPager.getChildAt(position).setAlpha(1); 
          mTabItems.get(position).setTabAlpha(1 - positionOffset); 
        } 
        if (mOnPageChangeListener != null) { 
mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); 
        } 
      } 
      @Override 
      public void onPageSelected(int position) { 
        if (mOnPageChangeListener != null) { 
mOnPageChangeListener.onPageSelected(position); 
        } 
      } 
      @Override 
      public void onPageScrollStateChanged(int state) { 
        if (mOnPageChangeListener != null) { 
mOnPageChangeListener.onPageScrollStateChanged(state); 
        } 
      } 
    }); 
    if (mPagerAdapter instanceof OnItemIconTextSelectListener) { 
      mListener = (OnItemIconTextSelectListener) mPagerAdapter; 
    }else { 
      throw new RuntimeException("    pageAdapter  OnItemIconTextSelectListener  "); 
    } 
    initItem(); 
  } 
  public void setOnPageChangeListener(ViewPager.OnPageChangeListener mOnPageChangeListener) { 
    this.mOnPageChangeListener = mOnPageChangeListener; 
  } 
  private void initItem() { 
    for (int i = 0; i < mChildSize; i++) { 
      TabItem tabItem = new TabItem(getContext()); 
      LayoutParams params = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1); 
      tabItem.setPadding(mPadding, mPadding, mPadding, mPadding); 
      tabItem.setIconText(mListener.onIconSelect(i), mListener.onTextSelect(i)); 
      tabItem.setTextSize(mTextSize); 
      tabItem.setTextColorNormal(mTextColorNormal); 
      tabItem.setTextColorSelect(mTextColorSelect); 
      tabItem.setLayoutParams(params); 
      tabItem.setTag(i); 
      tabItem.setOnClickListener(this); 
      mTabItems.add(tabItem); 
      addView(tabItem); 
    } 
  } 
  @Override 
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
  } 
  @Override 
  public void onClick(View v) { 
    int position = (Integer) v.getTag(); 
    if (mViewPager.getCurrentItem() == position) { 
      return; 
    } 
    for (TabItem tabItem : mTabItems) { 
      tabItem.setTabAlpha(0); 
    } 
    mTabItems.get(position).setTabAlpha(1); 
    mViewPager.setCurrentItem(position, false); 
  } 
  public interface OnItemIconTextSelectListener { 
    int[] onIconSelect(int position); 
    String onTextSelect(int position); 
  } 
} 
주석 이 좀 적 습 니 다.어,적은 것 이 아니 라 아예 없 는 것 입 니 다.사실은 이런 코드 는 주석 이 필요 없습니다.저 는 모두 가 알 아 볼 수 있 을 것 이 라 고 믿 습 니 다.저 는 그의 역할 을 이야기 하 겠 습 니 다.
  • 아 이 템 추가
  • ViewPager 의 스크롤 이 벤트 를 감청 하여 해당 아 이 템 간 의 색상 그 라 데 이 션 을 설정 합 니 다
  • 해당 ViewPage 의 투명 도 를 설정 합 니 다
  • TabItem 에 감청 사건 을 설정 합 니 다
  • 사실 위의 많은 기능 은 원래 MainActivity 에서 이 루어 졌 는데 Activity 내부 의 코드 량 을 줄 이기 위해 추출 하여 낮은 결합,높 은 내부 집적 효 과 를 얻 었 다.
    Ok,이상 은 위 챗 6.1 tab 표시 줄 색상 그 라 데 이 션 효과 의 실현 전 과정 입 니 다.
    이상 은 본 고의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.또한 저 희 를 많이 지지 해 주시 기 바 랍 니 다!

    좋은 웹페이지 즐겨찾기