此篇已經(jīng)過(guò)時(shí)
請(qǐng)看下一篇更新后的文章BMoveView,RadioGroup添加移動(dòng)的特效View(update)
google也曾推薦使用底部導(dǎo)航欄的方式進(jìn)行切換,使用RadioButton
可完成切換的動(dòng)作
RadioButton
除了變顏色,添加圖片顯示外,我們還可以添加如下的特定效果.動(dòng)畫可以增加APP的美感,提升用戶體驗(yàn)度
先上圖:
很多屬性可以自定義
我的github 源碼使用鏈接
BMoveView鏈接
很多的自定義View
歡迎點(diǎn)個(gè)Star
屬性 | 含義 |
---|---|
circleColor | 圓環(huán)的顏色 |
lineColor | 下面的線條的顏色 |
lineDuration | 線條頭的移動(dòng)時(shí)間(單位ms) |
lineWidth | 線條的寬度 |
circleDuration | 圓圈的動(dòng)畫時(shí)間(單位ms) |
circleCenterColor | 圓圈中心的顏色(可以不和背景一樣) |
circleRadio | 圓圈的半徑 |
以上就是所有的屬性
可以設(shè)置不同的移動(dòng)效果,根據(jù)個(gè)人需求來(lái)實(shí)現(xiàn)
使用
在布局文件XML里
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<com.yk.myselfview.views.BMoveView
android:id="@+id/bmoveview"
android:layout_width="match_parent"
android:layout_height="60dp"
yk:circleColor="#fd4040"
yk:lineColor="#fd4040"
yk:lineDuration="150"
yk:lineWidth="3"
yk:circleDuration="500"
yk:circleCenterColor="#FFFFFF"
yk:circleRadio="25"
/>
<RadioGroup
android:id="@+id/rg_group"
android:gravity="center"
android:weightSum="3"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<RadioButton
android:id="@+id/rb_first"
android:button="@null"
android:text="索引"
android:layout_weight="1"
android:textColor="@drawable/rb_button"
android:textSize="18sp"
android:gravity="center"
android:layout_width="0dp"
android:layout_height="match_parent"/>
<RadioButton
android:id="@+id/rb_second"
android:button="@null"
android:text="熱門"
android:layout_weight="1"
android:textColor="@drawable/rb_button"
android:textSize="18sp"
android:gravity="center"
android:layout_width="0dp"
android:layout_height="match_parent"/>
<RadioButton
android:id="@+id/rb_third"
android:button="@null"
android:text="我的"
android:layout_weight="1"
android:textColor="@drawable/rb_button"
android:textSize="18sp"
android:gravity="center"
android:layout_width="0dp"
android:layout_height="match_parent"/>
</RadioGroup>
</RelativeLayout>
其中
<com.yk.myselfview.views.BMoveView
android:id="@+id/bmoveview"
android:layout_width="match_parent"
android:layout_height="60dp"
yk:circleColor="#fd4040"
yk:lineColor="#fd4040"
yk:lineDuration="150"
yk:lineWidth="3"
yk:circleDuration="500"
yk:circleCenterColor="#FFFFFF"
yk:circleRadio="25"/>
為主要的布局,是我們的自定義的BMoveView
在Activity里,如下:
public class BMoveViewActivity extends Activity {
private int mFirstPos; //上一次的radiobutton位置
private int mLastPos; //點(diǎn)擊的radiobutton位置
private BMoveView mBMoveView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bmove_view);
bMoveInit();
}
private void bMoveInit() {
mBMoveView = (BMoveView) findViewById(R.id.bmoveview);
RadioGroup radioGroup= (RadioGroup) findViewById(R.id.rg_group);
((RadioButton) (radioGroup.getChildAt(0))).setChecked(true);
mFirstPos = 0;
mBMoveView.startAnim();
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
for (int i = 0; i < group.getChildCount(); i++) {
boolean checked = ((RadioButton) (group.getChildAt(i))).isChecked();
if(checked){
mLastPos = i; //當(dāng)前的點(diǎn)擊位置
mBMoveView.setTwoPos(mFirstPos, mLastPos);
mFirstPos = mLastPos; //記錄上一次的點(diǎn)擊位置,更新位置
}
}
}
});
}
}
是不是很簡(jiǎn)單,主要是記錄兩次的位置,就能實(shí)現(xiàn)這個(gè)效果了
使用方法講完了,下面介紹是如何實(shí)現(xiàn)的
主要是在onDraw里,繪制我們的view,分析動(dòng)畫和過(guò)程
- 一個(gè)圓圈的動(dòng)畫,就是旋轉(zhuǎn)
- 下面一個(gè)線條,添加移動(dòng)效果
- 線條移動(dòng)頭和尾的移動(dòng)時(shí)間不同
- 移動(dòng)的方向和位置
主要代碼如下
public class BMoveView extends View {
private int mWidth;
private int mHeight;
private Paint mPaint=new Paint();
private RectF mRectF;
private int boardWidth=50;
private int maxCircle=360;
private int firstPos; //第一次點(diǎn)擊位置
private int lastPos; //第二次點(diǎn)擊位置
private int lineControl; //下面控制線條的起始位置
private int mRoationx=0;
private int radio=5;
private int position=0;//點(diǎn)擊到了那個(gè)button
private int mLineEndLength;
private int mLineLength;
private int mCircleColor;
private int mLineColor;
private int mLineDuration;
private int mLineWidth;
private int mCircleDuration;
private int mCircleCenterColor;
private int mCircleRadio;
public void setTwoPos(int firstPos,int lastPos) {
this.firstPos = firstPos;
this.lastPos=lastPos;
devidePos();
}
//判斷兩次的位置,選擇不同動(dòng)畫
private void devidePos() {
setRoationx(0);
if(firstPos==0){
if(lastPos==1){
leftToRigth(lastPos, 1);
} else if(lastPos==2){
leftToRigth(lastPos, 2);
}
}else if(firstPos==1){
if(lastPos==0){
leftToRigth(lastPos, -1);
} else if(lastPos==2){
leftToRigth(lastPos, 1);
}
}
else if(firstPos==2){
if(lastPos==0){
leftToRigth(lastPos, -2);
} else if(lastPos==1){
leftToRigth(lastPos, -1);
}
}
}
/**
*
* @param lastPos 上一次的位置
* @param startLineineLastPosition 正為向右,負(fù)為想左,如果是1.則跨度為一,如果是2,則跨度為2;
*/
private void leftToRigth(int lastPos, int startLineineLastPosition) {
setPosition(lastPos);
startAnim();
lineControl=lastPos-startLineineLastPosition;//下面控制線條的起始位置
startLineAnim(startLineineLastPosition);
startLineEndAnim(startLineineLastPosition);
}
public void setRoationx(int roationx) {
mRoationx = roationx;
}
public void setPosition(int position) {
this.position = position;
}
public BMoveView(Context context) {
super(context);
init(context,null,0);
}
public BMoveView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs,0);
}
public BMoveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs,defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BMoveView, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.BMoveView_circleColor:
mCircleColor = a.getColor(attr, Color.WHITE);
break;
case R.styleable.BMoveView_lineColor:
mLineColor = a.getColor(attr, Color.GRAY);
break;
case R.styleable.BMoveView_circleCenterColor:
mCircleCenterColor = a.getColor(attr, Color.GRAY);
break;
case R.styleable.BMoveView_lineDuration:
mLineDuration = a.getInt(attr,500);
break;
case R.styleable.BMoveView_lineWidth:
mLineWidth = a.getInt(attr, 5);
break;
case R.styleable.BMoveView_circleDuration:
mCircleDuration = a.getInt(attr,500);
break;
case R.styleable.BMoveView_circleRadio:
mCircleRadio = a.getInt(attr,500);
break;
}
}
a.recycle();
boardWidth=dip2px(context,mCircleRadio);
radio=dip2px(context,mLineWidth);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//畫弧度
mPaint.setColor(mCircleColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
//位置計(jì)算比較麻煩,用比例
mRectF=new RectF(mWidth/6-boardWidth+position*mWidth/3,mHeight/2-boardWidth,mWidth/6+boardWidth+position*mWidth/3,mHeight/2+boardWidth);
canvas.drawArc(mRectF,90,mRoationx,true,mPaint);
//畫圓覆蓋
mPaint.reset();
mPaint.setColor(mCircleCenterColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(mWidth/6+(position)*mWidth/3,mHeight/2,boardWidth-radio,mPaint);
//畫線條
mPaint.setColor(mLineColor);
mPaint.setStrokeWidth(radio);
//起始和結(jié)束不同,每次動(dòng)畫結(jié)束位置是相同的,控制起始點(diǎn)和結(jié)束點(diǎn)
canvas.drawLine(mWidth/6+lineControl*mWidth/3+mLineEndLength,mHeight/2+boardWidth-radio/2,mWidth/6+lineControl*mWidth/3+mLineLength,mHeight/2+boardWidth-radio/2, mPaint);
}
//圓圈的動(dòng)畫
public void startAnim(){
ValueAnimator animator = ValueAnimator.ofInt(0,maxCircle);
animator.setDuration(mCircleDuration);
animator.setStartDelay(mLineDuration);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mRoationx = (int)animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
//線條開(kāi)始的動(dòng)畫
public void startLineAnim(int startLineineLastPosition){
ValueAnimator animator = ValueAnimator.ofInt(0,(mWidth/3)*startLineineLastPosition);
animator.setDuration(mLineDuration);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mLineLength = (int)animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
//線條結(jié)束的動(dòng)畫
public void startLineEndAnim(int endLineineLastPosition){
ValueAnimator animator = ValueAnimator.ofInt(0,(mWidth/3)*endLineineLastPosition);
animator.setDuration(mCircleDuration);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mLineEndLength = (int)animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
主要是在onDraw里的繪制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//畫弧度
mPaint.setColor(mCircleColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
//位置計(jì)算比較麻煩,用比例
mRectF=new RectF(mWidth/6-boardWidth+position*mWidth/3,mHeight/2-boardWidth,mWidth/6+boardWidth+position*mWidth/3,mHeight/2+boardWidth);
canvas.drawArc(mRectF,90,mRoationx,true,mPaint);
//畫圓覆蓋
mPaint.reset();
mPaint.setColor(mCircleCenterColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(mWidth/6+(position)*mWidth/3,mHeight/2,boardWidth-radio,mPaint);
//畫線條
mPaint.setColor(mLineColor);
mPaint.setStrokeWidth(radio);
//起始和結(jié)束不同,每次動(dòng)畫結(jié)束位置是相同的,控制起始點(diǎn)和結(jié)束點(diǎn)
canvas.drawLine(mWidth/6+lineControl*mWidth/3+mLineEndLength,mHeight/2+boardWidth-radio/2,mWidth/6+lineControl*mWidth/3+mLineLength,mHeight/2+boardWidth-radio/2, mPaint);
}
如上所示,選好了點(diǎn)的位置就是添加動(dòng)畫,一共寫了三個(gè)動(dòng)畫,圓圈的動(dòng)畫,線條頭的動(dòng)畫,線條尾的動(dòng)畫
//圓圈的動(dòng)畫
public void startAnim(){
ValueAnimator animator = ValueAnimator.ofInt(0,maxCircle);
animator.setDuration(mCircleDuration);
animator.setStartDelay(mLineDuration);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mRoationx = (int)animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
//線條開(kāi)始的動(dòng)畫
public void startLineAnim(int startLineineLastPosition){
ValueAnimator animator = ValueAnimator.ofInt(0,(mWidth/3)*startLineineLastPosition);
animator.setDuration(mLineDuration);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mLineLength = (int)animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
//線條結(jié)束的動(dòng)畫
public void startLineEndAnim(int endLineineLastPosition){
ValueAnimator animator = ValueAnimator.ofInt(0,(mWidth/3)*endLineineLastPosition);
animator.setDuration(mCircleDuration);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mLineEndLength = (int)animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
邏輯判斷,通過(guò)兩次的位置,來(lái)判斷該使用哪一個(gè)動(dòng)畫,同時(shí)配合Radiobutton
完成移動(dòng)的效果
//判斷兩次的位置,選擇不同動(dòng)畫
private void devidePos() {
setRoationx(0);
if(firstPos==0){
if(lastPos==1){
leftToRigth(lastPos, 1);
} else if(lastPos==2){
leftToRigth(lastPos, 2);
}
}else if(firstPos==1){
if(lastPos==0){
leftToRigth(lastPos, -1);
} else if(lastPos==2){
leftToRigth(lastPos, 1);
}
}
else if(firstPos==2){
if(lastPos==0){
leftToRigth(lastPos, -2);
} else if(lastPos==1){
leftToRigth(lastPos, -1);
}
}
}
/**
*
* @param lastPos 上一次的位置
* @param startLineineLastPosition 正為向右,負(fù)為想左,如果是1.則跨度為一,如果是2,則跨度為2;
*/
private void leftToRigth(int lastPos, int startLineineLastPosition) {
setPosition(lastPos);
startAnim();
lineControl=lastPos-startLineineLastPosition;//下面控制線條的起始位置
startLineAnim(startLineineLastPosition);
startLineEndAnim(startLineineLastPosition);
}