这个是iOS菜单栏的箭头, 拖动的时候会有动画, 因为懒我就不上GIF图了
这个是我自定义模仿的View, 效果如下:
先做一波分析:
附上一张分解图
1.把1/2箭头X轴的长度把控件切分成四份, 箭头所占Y轴的长度切分成四份
2.控件的高度是宽度的1/3
3.图中直线明显看出是圆头
4.确定每条直线的startX、startY、stopX、stopY, 注意因为为了更方便快捷控制弯曲程度所以控制点只有一个, 意思就是两条直线的stopX、stopY是同一个X、Y, 这样子只要改变这个点的Y参数就能达到改变弯曲程度了
5.看图能看出左一直线的startX为控件宽度1/4、startY为控制高度2/4, 左二startX为控件宽度3/4、startY为控件高度2/4, stopX都为控件宽度2/4、stopY都为控件高度3/4
分解完毕, 开始写代码:
测量控件宽高, 经过调试较佳效果为高是宽的1/3
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
// 高是宽的30%
setMeasuredDimension(size, size / 3);
}
设置画笔线头形状为圆头
// 设置线头形状为圆头
mPaint.setStrokeCap(Paint.Cap.ROUND);
确定X、Y位置
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
startX = w / 4;
startY = h / 4;
setStopX(startX * 2);
setStopY(startY * 3);
}
绘制直线
canvas.drawLine((float) startX, (float) startY * 2,
(float) getStopX(), (float) getStopY(), mPaint);
canvas.drawLine((float) startX * 3, (float) startY * 2,
(float) getStopX(), (float) getStopY(), mPaint);
滑动屏幕的时候会改变箭头的弯曲程度, 重写要滑动View的onTouchEvent事件
/**
* BottomView的触摸事件
* 记得return true消费该事件
*/
private class BottomViewOnTouchEvent implements OnTouchListener {
int downY;
// Y的距离差
float distanceDifference;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
// Y轴距离差
distanceDifference = event.getRawY() - downY;
// 箭头弯曲比例是屏幕宽度3.5
double ratio = width / 3.5;
// 判断手指是向下滑动
if (event.getRawY() > downY) {
// bottomView随手指移动
bottomView.layout(0, (int) (event.getRawY() - downY),
width, (int) (height + (event.getRawY() - downY)));
// 箭头随手指移动改变弯曲率, 控制在最高点和最低点范围内移动
if ((ratio - distanceDifference) / 7 >= mArrowView.getStartY()
&& (ratio - distanceDifference) / 7 <= mArrowView.getStartY() * 3) {
mArrowView.setStopY((ratio - distanceDifference) / 7);
}
}
break;
case MotionEvent.ACTION_UP:
// Y轴距离差大于200, bottomView向下滑动收起
if (distanceDifference >= 200) {
bottomView.layout(0, height, width, height * 2);
roundView.layout(0, height, roundViewSize, roundViewSize + height);
mArrowView.setStopY(mArrowView.getStartY() * 3);
roundView.setVisibility(VISIBLE);
// 不大于200, 弹回顶部
} else {
bottomView.layout(0, 0, width, height);
mArrowView.setStopY(mArrowView.getStartY() * 3);
}
break;
}
return true;
}
}
xml引用要注意不需要指定高度
<cn.startrails.webb.widget.ArrowView
android:id="@+id/av_bottom"
android:layout_width="55dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
post上源码:
package cn.startrails.webb.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* 箭头View
* 建议xml中宽高为
* android:layout_width="55dp"
* android:layout_height="wrap_content"
*
* @author WebbLin(林恩)
* @date 2018/5/5 17:49
* @email Webb@starcc.cc
*/
public class ArrowView extends View {
private Paint mPaint;
private double startX, startY, stopX, stopY;
public ArrowView(Context context) {
super(context);
init();
}
public ArrowView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ArrowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// 设置笔划宽度
mPaint.setStrokeWidth(12);
// 设置线头形状为圆头
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setColor(Color.parseColor("#808080"));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
startX = w / 4;
startY = h / 4;
setStopX(startX * 2);
setStopY(startY * 3);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine((float) startX, (float) startY * 2,
(float) getStopX(), (float) getStopY(), mPaint);
canvas.drawLine((float) startX * 3, (float) startY * 2,
(float) getStopX(), (float) getStopY(), mPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
// 高是宽的1/3
setMeasuredDimension(size, size / 3);
}
public double getStartX() {
return startX;
}
public void setStartX(double startX) {
this.startX = startX;
}
public double getStartY() {
return startY;
}
public void setStartY(double startY) {
this.startY = startY;
}
public double getStopX() {
return stopX;
}
public void setStopX(double stopX) {
this.stopX = stopX;
invalidate();
}
public double getStopY() {
return stopY;
}
public void setStopY(double stopY) {
this.stopY = stopY;
invalidate();
}
}