1.ActionBar
设置样式,改变overflowButtonstyle;反射,改变 带图标下拉item。
2.ViewPager+Fragement
推荐:使用
设置setArguments Bundle (代替传参)
//从第一页到第二页 positionOffset 0~1 //从第二页到第一页 positionOffset 1~0
3.TabIndicator(自定义控件)
一.底部滑动渐变
原理:底部摆放四个自定义控件,控件内部在一个Bitmap上绘制纯色并设置Xfermodes 为DstIn,然后在Bitmap上绘制对应icon,最后通过View的Canvas绘制出来,利用ViewPager的onPageScrolled时的参数positionOffset的变化设置自定义控件的透明度。
自定义View
1.自定义attr.xml
2.布局文件中使用
3.构造方法中获取自定义属性
4.onMeasure中计算Icon区域大小(Rect mIconRect)
5.onDraw 使用从自定义属性中获取的Bitmap来绘制Icon 根据文字画笔 绘制原文字以及变化的文字
dimension(单位sp)
declare-styleable name="自定义View的名称"
1.自定义attr.xml
<resources> <attr name="icon1" format="reference"></attr> <attr name="color1" format="color"></attr> <attr name="text" format="string"></attr> <attr name="text_size" format="dimension"></attr> <declare-styleable name="ChangeColorIconWithText"> <attr name="icon1"></attr> <attr name="color1"></attr> <attr name="text"></attr> <attr name="text_size"></attr> </declare-styleable> </resources>2.布局文件中使用
<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" >
<LinearLayout android:layout_width="match_parent" android:layout_height="60dp" android:background="@drawable/tab_bg" android:orientation="horizontal" > <wechat6_0.example.com.wechat6_0.ChangeColorIconWithText android:id="@+id/id_indicator_one" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" android:padding="5dp" hyman:icon1="@mipmap/ic_menu_start_conversation" hyman:text="@string/app_name" hyman:text_size="12sp" hyman:color1="#ff45c01a" /> <wechat6_0.example.com.wechat6_0.ChangeColorIconWithText android:id="@+id/id_indicator_two" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" android:padding="5dp" hyman:icon1="@mipmap/ic_menu_friendslist" hyman:text="@string/tab_contact" hyman:text_size="12sp" hyman:color1="#ff45c01a" />
3.构造方法中获取自定义属性(根据文字长度设置文字画笔Paint
,并获取文字区域大小)
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_icon1: BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr); mIconBitmap = drawable.getBitmap(); break; case R.styleable.ChangeColorIconWithText_color1: 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; } } //使用context.obtainStyledAttributes(attrs,R.styleable.ChangeColorIconWithText) // 记得recycle a.recycle(); mTextBound = new Rect(); mTextPaint = new Paint(); mTextPaint.setTextSize(mTextSize); mTextPaint.setColor(0Xff555555);//灰色 mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound); }4. onMeasure中计算Icon区域大小(Rect mIconRect)
private int mColor = 0xFF45C01A; private Bitmap mIconBitmap; private String mText = "微信"; //设置默认12sp COMPLEX_UNIT_SP 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 Paint mTextPaint; private Rect mIconRect; private Rect mTextBound;
/* View有两种可能宽大于高 宽小于高 View的宽度-leftpadding-rightpadding View的高度-topPadding-mTextBound.height icon的边长为下列两个的最小值 */ @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); }
5.onDraw 使用从自定义属性中获取的Bitmap来绘制Icon 根据文字画笔 绘制原文字以及变化的文字
内存中绘制变色的icon
@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); }
/** * 在内存中绘制可变色的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));
//显示两者的交集且前者(mColor)的颜色 mPaint.setAlpha(255); mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint); }
/** * 绘制变色的文本 * * @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); } /** * 绘制原文本 * getMeasuredWidth View宽度 * @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的Alpha并根据主\其他线程 刷新控件
public void setIconAlpha(float alpha) { this.mAlpha = alpha; invalidateView(); } /** * 重绘 */ private void invalidateView() { if (Looper.getMainLooper() == Looper.myLooper()) { invalidate(); } else { postInvalidate(); } }
防止Activity回收(长期至于后台的被回收)总结
(模拟回收-当旋转时Activiy会重建)
实现目的:activity的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); }