Android App 위 챗 인터페이스 전환 시 Tab 아이콘 변색 효과 만 드 는 방법
1.개술
안 드 로 이 드 를 배 우 는 것 은 각종 app 의 화면 을 모방 하 는 것 이 빠 질 수 없습니다.위 챗 6.0 이 출시 된 후부 터 위 챗 이 바 뀌 었 을 때 그 변 색 된 Tab 아이콘 노 모 는 오늘 제 가 여러분 에 게 사용자 정의 컨트롤 을 가지 고 변색 되 어 날 아 갈 것 이 라 고 생각 합 니 다~
자,다음은 효과 도 를 보 겠 습 니 다.
선명 도가 별로 좋 지 않 습 니 다.여러분,아 쉬 운 대로 보 세 요.이 색깔 이 약 하 다 고 생각 하 는 나무 가 있 습 니 다.다음 에 제 가 손가락 을 움 직 여 색깔 을 바 꿔 드릴 게 요.
이 색깔 이 좀 요염 하지 않 아 요?
2.원리 소개
위의 효과 도 를 통 해 여러분 도 알 수 있 습 니 다.우리 의 아이콘 은 두 장의 그림 이 아니 라 한 장의 그림 입 니 다.그리고 목표 색 채 는 맞 춤 형 입 니 다.누가 지금 걸핏하면 개성 화 를 이야기 하 라 고 합 니까?
그러면 우리 가 어떻게 하면 아이콘 이 마음 에 드 는 대로 변색 할 수 있 습 니까?사실은 원 리 는 제 블 로그 에 여러 번 나 타 났 습 니 다.다음은 익숙 한 그림 을 볼 수 있 습 니 다.
익숙 한 감각 이 있 습 니까?우 리 는 실제로 Paint 의 Xfermode 를 이 용 했 습 니 다.이번에 우리 가 사용 한 것 은:Mode.DST 입 니 다.IN
Dst_IN 은 어떤 효 과 를 돌 이 켜 보고 Dst 를 그리고 Mode 를 설정 한 다음 에 Src 를 그리 면 선후 로 그림 을 그 리 는 교차 구역 과 Dst 를 보 여 줍 니 다.
우리 의 아이콘 을 자세히 살 펴 보 자.
여러분 의 관람 을 편리 하 게 하기 위해 저 는 ps 를 들 고 저희 아이콘 의 불투명 구역 을 선 택 했 습 니 다.이 작은 로봇 의 불투명 구역 은 바로 선 에 걸 린 부분 입 니 다.
그리고 우리 아이콘 의 변색 원리 가 나 타 났 다.
(1)먼저 색상 을 그립 니 다(예:분홍색)
(2)모드 설정=DSTIN
(3)귀여운 우리 로봇 그리 기
대답 해 봐,뭘 보 여?교 집합 을 보 여 주 는 거 아니 야?교 집합 이 뭐야?교 집합 은 우리 의 작은 로봇 의 비 투명 구역,즉 그 얼굴 이다.두 눈 을 제외 하고.
됐어,그럼 어떻게 변색 하지?
제 가 색상 을 그 릴 때 알 파 를 설정 할 수 없 나 요~~
이제 우리 아이콘 이 그 려 지 는 원 리 를 알 고 계 시 겠 죠?
3.사용자 정의 아이콘 컨트롤
우리 의 전체 화면 은 말 할 것 도 없 이 ViewPager+Fragment 입 니 다.지금 주목 하 는 것 은 아래쪽 입 니 다~~
다음은 밑 에 있 는 Tab,Tab 를 고려 해 보 겠 습 니 다.우리 의 구 조 는 LinearLayout 이 고 내부 에 있 는 네 개의 View 입 니 다.weight 설정 을 통 해 평균 점 수 를 얻 을 수 있 습 니 다~~
이 View 는 사용자 정의 아이콘 컨트롤 입 니 다.저 희 는 Change ColorIcon With TextView 라 고 합 니 다.
포인트
다음은 어떤 속성 이 발표 되 어야 할 지 고려 해 보 겠 습 니 다.
1.사용자 정의 속성
생각해 보 니 아이콘,아이콘 색상,아이콘 에 표 시 된 텍스트,텍스트 크기 등 네 가지 속성 을 사용자 정의 속성 으로 사용 하기 로 했 습 니 다.
사용자 정의 속성 이 시 작 됩 니 다:
a、values/attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="icon" format="reference" />
<attr name="color" format="color" />
<attr name="text" format="string" />
<attr name="text_size" format="dimension" />
<declare-styleable name="ChangeColorIconView">
<attr name="icon" />
<attr name="color" />
<attr name="text" />
<attr name="text_size" />
</declare-styleable>
</resources>
b.레이아웃 파일 에서 사용
<com.zhy.weixin6.ui.ChangeColorIconWithTextView
android:id="@+id/id_indicator_one"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:padding="5dp"
zhy:icon="@drawable/ic_menu_start_conversation"
zhy:text="@string/tab_weixin"
zhy:text_size="12sp" />
네 임 스페이스 쓰기 에 주의 하 세 요.xmlns:zhy="http://schemas.android.com/apk/res/적 용 된 가방 이름"이 라 고 말 했다.c.구조 방법 에서 획득
public class ChangeColorIconWithTextView extends View
{
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mPaint;
/**
*
*/
private int mColor = 0xFF45C01A;
/**
* 0.0-1.0
*/
private float mAlpha = 0f;
/**
*
*/
private Bitmap mIconBitmap;
/**
* icon
*/
private Rect mIconRect;
/**
* icon
*/
private String mText = " ";
private int mTextSize = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics());
private Paint mTextPaint;
private Rect mTextBound = new Rect();
public ChangeColorIconWithTextView(Context context)
{
super(context);
}
/**
*
*
* @param context
* @param attrs
*/
public ChangeColorIconWithTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
//
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ChangeColorIconView);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.ChangeColorIconView_icon:
BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);
mIconBitmap = drawable.getBitmap();
break;
case R.styleable.ChangeColorIconView_color:
mColor = a.getColor(attr, 0x45C01A);
break;
case R.styleable.ChangeColorIconView_text:
mText = a.getString(attr);
break;
case R.styleable.ChangeColorIconView_text_size:
mTextSize = (int) a.getDimension(attr, TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10,
getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
mTextPaint = new Paint();
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(0xff555555);
// text
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
}
구조 방법 에서 사용자 정의 속성 을 얻 었 고 텍스트 가 차지 하 는 컨트롤 이 mTextBound 에 존재 하 는 것 을 계산 할 수 있 습 니 다.2.아이콘 그리 기 영역 선택
우 리 는 속성 이 있 는 것 을 고려 해 보 았 습 니 다.우 리 는 텍스트 를 그 려 야 합 니 다.텍스트 위 에 있 는 아이콘 을 그 려 야 합 니 다.우 리 는 그 려 진 영역 을 어떻게 제어 합 니까?
우리 의 View 디 스 플레이 영역 은 다음 과 같은 세 가지 상황 이 아 닙 니 다.
이 세 가지 상황 에 대해 우리 문의 아이콘 의 길 이 는 무엇 일 까요?
나 는 변 길이 가 컨트롤 의 높이-텍스트 의 높이-내 변 거리 라 고 생각한다. ...과 컨트롤 폭-안쪽 여백 둘 의 작은 값;모두 곰 곰 이 생각해 보 세 요.
자,위의 길이 에 대한 결론 이 나 면 우 리 는 아이콘 의 그리 기 범 위 를 계산 하기 시작 합 니 다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// icon
int bitmapWidth = Math.min(getMeasuredWidth() - getPaddingLeft()
- getPaddingRight(), getMeasuredHeight() - getPaddingTop()
- getPaddingBottom() - mTextBound.height());
int left = getMeasuredWidth() / 2 - bitmapWidth / 2;
int top = (getMeasuredHeight() - mTextBound.height()) / 2 - bitmapWidth
/ 2;
// icon
mIconRect = new Rect(left, top, left + bitmapWidth, top + bitmapWidth);
}
3、아이콘 그리 기아이콘 을 그 리 는 데 절차 가 많 군요.제 가 열 을 만 들 겠 습 니 다.
(1)알파 계산(기본 값 0)
(2)원 도 를 그립 니 다
(3)그림 그리 기 영역 에서 순수한 색 블록 을 그립 니 다(알파 설정).이 단 계 는 메모리 의 bitmap 에 그립 니 다.
(4)메모리 에 있 는 bitmap 의 paint 를 위 한 mode 설정
(5)메모리 의 bitmap 에 아이콘 을 그립 니 다.
(6)원본 그리 기
(7)알파 와 색상 을 설정 한 텍스트 그리 기
(8)메모리 에 있 는 bitmap 그리 기
위의 절차 에 따라 알 수 있 듯 이 우리 의 아이콘 은 사실 두 번 그 렸 는데 왜 원 도 를 그 렸 을 까?왜냐하면 나 는 비교적 보기 좋 기 때문이다.
3-5 단계,바로 우리 가 위 에서 분석 한 원리 이다.
6-7 단 계 는 텍스트 를 그립 니 다.볼 수 있 습 니 다.우리 의 텍스트 는 알파 설정 을 통 해 이 루어 집 니 다.
@Override
protected void onDraw(Canvas canvas)
{
int alpha = (int) Math.ceil((255 * mAlpha));
canvas.drawBitmap(mIconBitmap, null, mIconRect, null);
setupTargetBitmap(alpha);
drawSourceText(canvas, alpha);
drawTargetText(canvas, alpha);
canvas.drawBitmap(mBitmap, 0, 0, null);
}
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 void drawSourceText(Canvas canvas, int alpha)
{
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(0xff333333);
mTextPaint.setAlpha(255 - alpha);
canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2
- mTextBound.width() / 2,
mIconRect.bottom + mTextBound.height(), mTextPaint);
}
private void drawTargetText(Canvas canvas, int alpha)
{
mTextPaint.setColor(mColor);
mTextPaint.setAlpha(alpha);
canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2
- mTextBound.width() / 2,
mIconRect.bottom + mTextBound.height(), mTextPaint);
}
텍스트 영역 그리 기 에 대한 계산 은 먼저 시작 점 x:mIconRect.left+mIconRect.width()/2-mTextBound.width()/2 가 좀 길 어 요.텍스트 mIconRect.left+mIconRect.width()/2 이 위 치 는 아이콘 수평 영역의 중심 점 에 있 습 니 다.이것 은 의문 이 없 을 것 입 니 다.아이콘 수평 영역의 중심 점-mTextBound.width()/2 에서 텍스트 를 그리 기 시작 합 니 다.아이콘 아래 에 있 는 것 이 아 닙 니까?어떤 사람 이 물 어 볼 수 있 습 니 다.텍스트 너비 가 아이콘 보다 작은 것 을 어떻게 알 았 습 니까?저 는 5 글자 가 있 는데 어떻게 해 야 합 니까?5 글자 가 왜 요?똑 같이 가운데 로 나 와 요.못 믿 겠 으 면 해 보 세 요~~
4.투명 성 설정 방법 발표
여기 서 아이콘 컨트롤 을 다 썼 지만 아이콘 을 제어 하 는 방법 은 없습니다.
public void setIconAlpha(float alpha)
{
this.mAlpha = alpha;
invalidateView();
}
private void invalidateView()
{
if (Looper.getMainLooper() == Looper.myLooper())
{
invalidate();
} else
{
postInvalidate();
}
}
저 희 는 setIconAlpha 라 고 합 니 다.setAlpha 와 충돌 하지 않도록 설정 이 완료 되면 invalidate~~이제 정말 끝 났 습 니 다.다음은 용법 을 보 겠 습 니 다.
실전
1.레이아웃 파일
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:zhy="http://schemas.android.com/apk/res/com.zhy.weixin6.ui"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="@+id/id_viewpager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</android.support.v4.view.ViewPager>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dp"
android:background="@drawable/tabbg"
android:orientation="horizontal" >
<com.zhy.weixin6.ui.ChangeColorIconWithTextView
android:id="@+id/id_indicator_one"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:padding="5dp"
zhy:icon="@drawable/ic_menu_start_conversation"
zhy:text="@string/tab_weixin"
zhy:text_size="12sp" />
<com.zhy.weixin6.ui.ChangeColorIconWithTextView
android:id="@+id/id_indicator_two"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:padding="5dp"
zhy:icon="@drawable/ic_menu_friendslist"
zhy:text="@string/tab_contact"
zhy:text_size="12sp" />
<com.zhy.weixin6.ui.ChangeColorIconWithTextView
android:id="@+id/id_indicator_three"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:padding="5dp"
zhy:icon="@drawable/ic_menu_emoticons"
zhy:text="@string/tab_find"
zhy:text_size="12sp" />
<com.zhy.weixin6.ui.ChangeColorIconWithTextView
android:id="@+id/id_indicator_four"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:padding="5dp"
zhy:icon="@drawable/ic_menu_allfriends"
zhy:text="@string/tab_me"
zhy:text_size="12sp" />
</LinearLayout>
</LinearLayout>
2、MainActivity
package com.zhy.weixin6.ui;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
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.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.Window;
@SuppressLint("NewApi")
public class MainActivity extends FragmentActivity implements
OnPageChangeListener, OnClickListener
{
private ViewPager mViewPager;
private List<Fragment> mTabs = new ArrayList<Fragment>();
private FragmentPagerAdapter mAdapter;
private String[] mTitles = new String[] { "First Fragment!",
"Second Fragment!", "Third Fragment!", "Fourth Fragment!" };
private List<ChangeColorIconWithTextView> mTabIndicator = new ArrayList<ChangeColorIconWithTextView>();
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setOverflowShowingAlways();
getActionBar().setDisplayShowHomeEnabled(false);
mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
initDatas();
mViewPager.setAdapter(mAdapter);
mViewPager.setOnPageChangeListener(this);
}
private void initDatas()
{
for (String title : mTitles)
{
TabFragment tabFragment = new TabFragment();
Bundle args = new Bundle();
args.putString("title", title);
tabFragment.setArguments(args);
mTabs.add(tabFragment);
}
mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
{
@Override
public int getCount()
{
return mTabs.size();
}
@Override
public Fragment getItem(int arg0)
{
return mTabs.get(arg0);
}
};
initTabIndicator();
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void initTabIndicator()
{
ChangeColorIconWithTextView one = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_one);
ChangeColorIconWithTextView two = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_two);
ChangeColorIconWithTextView three = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_three);
ChangeColorIconWithTextView four = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_four);
mTabIndicator.add(one);
mTabIndicator.add(two);
mTabIndicator.add(three);
mTabIndicator.add(four);
one.setOnClickListener(this);
two.setOnClickListener(this);
three.setOnClickListener(this);
four.setOnClickListener(this);
one.setIconAlpha(1.0f);
}
@Override
public void onPageSelected(int arg0)
{
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels)
{
// Log.e("TAG", "position = " + position + " , positionOffset = "
// + positionOffset);
if (positionOffset > 0)
{
ChangeColorIconWithTextView left = mTabIndicator.get(position);
ChangeColorIconWithTextView right = mTabIndicator.get(position + 1);
left.setIconAlpha(1 - positionOffset);
right.setIconAlpha(positionOffset);
}
}
@Override
public void onPageScrollStateChanged(int state)
{
}
@Override
public void onClick(View v)
{
resetOtherTabs();
switch (v.getId())
{
case R.id.id_indicator_one:
mTabIndicator.get(0).setIconAlpha(1.0f);
mViewPager.setCurrentItem(0, false);
break;
case R.id.id_indicator_two:
mTabIndicator.get(1).setIconAlpha(1.0f);
mViewPager.setCurrentItem(1, false);
break;
case R.id.id_indicator_three:
mTabIndicator.get(2).setIconAlpha(1.0f);
mViewPager.setCurrentItem(2, false);
break;
case R.id.id_indicator_four:
mTabIndicator.get(3).setIconAlpha(1.0f);
mViewPager.setCurrentItem(3, false);
break;
}
}
/**
* Tab
*/
private void resetOtherTabs()
{
for (int i = 0; i < mTabIndicator.size(); i++)
{
mTabIndicator.get(i).setIconAlpha(0);
}
}
@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)
{
}
}
}
return super.onMenuOpened(featureId, menu);
}
private void setOverflowShowingAlways()
{
try
{
// true if a permanent menu key is present, false otherwise.
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class
.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e)
{
e.printStackTrace();
}
}
}
Activity 에 있 는 코드 는 설명 이 없 지만 간단 합 니 다.Fragment 를 초기 화하 고 우리 의 어댑터 를 얻 은 다음 ViewPager 에 설정 하 는 것 입 니 다.initTabIndicator 사용자 정의 컨트롤 을 초기 화하 고 클릭 이 벤트 를 추가 합 니 다.
유일 하 게 지적 해 야 할 것 은:
저 희 는 onPageScrolled 에서 position 와 position Offset 를 동적 으로 가 져 온 다음 에 좌우 두 개의 View 를 가 져 와 position Offset 을 설정 합 니 다.
여기 서 부 끄 럽 습 니 다.위 챗 5.2.1 메 인 인터페이스 구조 에 메시지 알림 이 포 함 된 onPage Scrolled 에 if else 를 한 무더기 썼 습 니 다.영상 이 출시 된 후에 도 친구 들 이 바로 제 기 했 습 니 다.한 줄 의 코드 가 해결 되 었 습 니 다~~
그래서 우 리 는 간단하게 규칙 을 찾 았 습 니 다.이미 if else 의 모습 이 없습니다~~
두 가지 반사 방법 이 남 았 습 니 다.Actionbar 아이콘 을 제어 하고 menu 버튼 을 누 르 면 ActionBar 의 menu 를 정상 구역 에 표시 합 니 다~~
3、TabFragment
package com.zhy.weixin6.ui;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class TabFragment extends Fragment
{
private String mTitle = "Default";
public TabFragment()
{
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
if (getArguments() != null)
{
mTitle = getArguments().getString("title");
}
TextView textView = new TextView(getActivity());
textView.setTextSize(20);
textView.setBackgroundColor(Color.parseColor("#ffffffff"));
textView.setGravity(Gravity.CENTER);
textView.setText(mTitle);
return textView;
}
}
자,이제 우리 의 모든 사례 가 끝 났 습 니 다~~레이아웃 파일 에 다양한 색상 을 설정 할 수 있 습 니 다.4 가지 색상 으로 도 가능 합 니 다.마음껏 놀아 보 세 요~~
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.