我们用的都是系统自己的专用于标题懒得不能单独使用,我就自己定义了一个类似的控件。做的不是很好希望大家多多交流,有问题的可以提出。
下面上传效果图
上面的菜单键变化为两种,一种是拖动的转变,还有就是点击的转变。
下面看一下分析图
1.由菜单键到返回键转变,以180度为周期。旋转中心为中线中心点,主要变化的地方是:
a.在一个周期内时,绿点向黄点靠拢,
b.灰点向紫色的点靠拢。这里的向紫色点靠拢实现了箭头两翼线段的缩短,和与中线的夹角为45度。
2.要想实现实时的过程,那我们就要引入一个变量角度值,一个周期180度,我们把上面的靠拢值除以180,再乘以一个变化的角度值就ok了。
3.两侧与中线夹角为45度,为我们计算紫色点的位置提供了帮助。箭头顶点和紫色点到旋转中心距离等同。
4.已知的虚线起点和终点位置以及中心点,基本就搞定了。
5.动画的过程用线程完成。拖动的过程就可以设置角度完成。
6.注意这里线程里面要使用postInvalidate();来做异步处理,invalidate();时做同步处理的,只能用在主UI线程。
下面上代码
public class back_View extends View {
private int width;
private int height;
private float space;
private float marginLeftAndRight = 10;//左右边距
private float angle;//旋转角度
private float cx;//箭头结束点的x轴坐标
private float cy;//箭头结束点的y轴坐标
private float lineW;//中线的长度
//旋转180度后由菜单键变成返回键,因此收尾调转
private float count;//箭头顶点(中线的终点)到上下两条线终点的就离分成180份,每份代表旋转1度,上下两线的起点向中线终点靠拢的距离y的值
//箭头两翼末端到中线垂直距离(cy - space * 2),分成180份来移动
private float px;//(相对位置)当前两翼末端移动的距离,需要在原来两翼末端x轴数值做运算
private float py;//
/*设置,绘制的左右边距*/
public void setMarginLeftAndRight(float marginLeftAndRight) {
this.marginLeftAndRight = marginLeftAndRight;
}
public back_View(Context context) {
super(context);
}
public back_View(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public back_View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = right - left;
height = bottom - top;
space = (float) (height / 6.0);
lineW = width;
cx = lineW / 2;
cy = space * 3 - cx + marginLeftAndRight;
// Log.e("1111", "=========" + width);
invalidate();
}
//获取画笔类
private Paint getPaint() {
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAntiAlias(true);
paint.setStrokeWidth(6);
return paint;
}
public void click() {
new Thread(new Runnable() {
@Override
public void run() {
if (width > 0) {
if (angle >= 180) {
form180To360();
} else if (angle <= 0) {
form0To180();
}
}
}
}).start();
}
/*从0到180度*/
public void form0To180() {
while (true) {
angle++;
count += (space / 180);
px += (cx - marginLeftAndRight) / 180;
py += (cy - space * 2) / 180;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
postInvalidate();
if (angle >= 180) {
angle = 180;
break;
}
}
}
/*从180返回0度*/
public void form180To0() {
while (true) {
angle--;
count -= (space / 180);
px -= (cx - marginLeftAndRight) / 180;
py -= (cy - space * 2) / 180;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
postInvalidate();
if (angle <= 0) {
angle = 0;
break;
}
}
}
/*从180返回360度*/
public void form180To360() {
while (true) {
angle++;
count -= (space / 180);
px -= (cx - marginLeftAndRight) / 180;
py -= (cy - space * 2) / 180;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
postInvalidate();
if (angle >= 360) {
angle = 0;
break;
}
}
}
/*设置旋转角度*/
public void setAngle(float angle_) {
angle = angle_;
count = (space / 180) * angle;
px = (cx - marginLeftAndRight) / 180 * angle;
py = (cy - space * 2) / 180 * angle;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.rotate(angle, cx, (space * 3));//旋转中心
//上
canvas.drawLine(px + marginLeftAndRight, space * 2 + py, lineW - marginLeftAndRight, space * 2 + count, getPaint());
//中线
canvas.drawLine(0 + marginLeftAndRight, (float) (space * 3), lineW - marginLeftAndRight, (float) (space * 3), getPaint());
//下
canvas.drawLine(px + marginLeftAndRight, space * 4 - py, lineW - marginLeftAndRight, (float) (space * 4 - count), getPaint());
}
}
效果图
activity部分,布局就一个上面自定义控件引用,和一个SeekBar控件。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
view = findViewById(R.id.back_v);
seekBar = findViewById(R.id.seekBar);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
view.click();
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
view.setAngle((float) (1.8 * progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}