在网上大多数资料实现竖直seekBar的方法都是继承于seekBar然后对其进行重写,但后来看到另一种实现思路,就是在普通的seekBar的外层包裹一层layout,然后对外面的那个layout去进行翻转,达到实现竖直的seekBar的方式。
- 先定义一个MySeekBar去继承父类,无需重写,只要添加几个方法就行
public class MySeekBar extends AppCompatSeekBar {
public static final int ROTATION_ANGLE_CW_90 = 90;
public static final int ROTATION_ANGLE_CW_270 = 270;
private int mRotationAngle = ROTATION_ANGLE_CW_90;
public MySeekBar(Context context) {
super(context);
initialize(context, null, 0, 0);
}
public MySeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs, 0, 0);
}
public MySeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(context, attrs, defStyleAttr, 0);
}
private void initialize(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR);
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, defStyleRes);
final int rotationAngle = a.getInteger(R.styleable.VerticalSeekBar_seekBarRotation, 0);
if (isValidRotationAngle(rotationAngle)) {
mRotationAngle = rotationAngle;
}
a.recycle();
}
}
private static boolean isValidRotationAngle(int angle) {
return (angle == ROTATION_ANGLE_CW_90 || angle == ROTATION_ANGLE_CW_270);
}
boolean useViewRotation() {
final boolean isSupportedApiLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
final boolean inEditMode = isInEditMode();
return isSupportedApiLevel && !inEditMode;
}
public int getRotationAngle() {
return mRotationAngle;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return onTouchEventUseViewRotation(event);
}
private boolean onTouchEventUseViewRotation(MotionEvent event) {
boolean handled = super.onTouchEvent(event);
if (handled) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
attemptClaimDrag(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
attemptClaimDrag(false);
break;
}
}
return handled;
}
private void attemptClaimDrag(boolean active) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(active);
}
}
}
- 定义一个外层容器去包裹我们所创建的MySeekBar
public class MySeekBarWrapper extends FrameLayout {
public MySeekBarWrapper(@NonNull Context context) {
this(context, null, 0);
}
public MySeekBarWrapper(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MySeekBarWrapper(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (useViewRotation()) {
onSizeChangedUseViewRotation(w, h, oldw, oldh);
} else {
onSizeChangedTraditionalRotation(w, h, oldw, oldh);
}
}
private void onSizeChangedTraditionalRotation(int w, int h, int oldw, int oldh) {
final MySeekBar seekBar = getChildSeekBar();
if (seekBar != null) {
final int hPadding = getPaddingLeft() + getPaddingRight();
final int vPadding = getPaddingTop() + getPaddingBottom();
final LayoutParams lp = (LayoutParams) seekBar.getLayoutParams();
lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
lp.height = Math.max(0, h - vPadding);
seekBar.setLayoutParams(lp);
seekBar.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
final int seekBarMeasureWidth = seekBar.getMeasuredWidth();
seekBar.measure(MeasureSpec.makeMeasureSpec(Math.max(0, w - hPadding), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(Math.max(0, h - vPadding), MeasureSpec.EXACTLY));
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.leftMargin = (Math.max(0, w - hPadding) - seekBarMeasureWidth) / 2;
seekBar.setLayoutParams(lp);
}
super.onSizeChanged(w, h, oldw, oldh);
}
private void onSizeChangedUseViewRotation(int w, int h, int oldw, int oldh) {
final MySeekBar seekBar = getChildSeekBar();
if (seekBar != null) {
final int hPadding = getPaddingLeft() + getPaddingRight();
final int vPadding = getPaddingTop() + getPaddingBottom();
seekBar.measure(
MeasureSpec.makeMeasureSpec(Math.max(0, h - vPadding), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(Math.max(0, w - hPadding), MeasureSpec.EXACTLY));
}
applyViewRotation(w, h);
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final MySeekBar seekBar = getChildSeekBar();
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if ((seekBar != null) && (widthMode != MeasureSpec.EXACTLY)) {
final int seekBarWidth;
final int seekBarHeight;
final int hPadding = getPaddingLeft() + getPaddingRight();
final int vPadding = getPaddingTop() + getPaddingBottom();
final int innerContentWidthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(0, widthSize - hPadding), widthMode);
final int innerContentHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(0, heightSize - vPadding), heightMode);
if (useViewRotation()) {
seekBar.measure(innerContentHeightMeasureSpec, innerContentWidthMeasureSpec);
seekBarWidth = seekBar.getMeasuredHeight();
seekBarHeight = seekBar.getMeasuredWidth();
} else {
seekBar.measure(innerContentWidthMeasureSpec, innerContentHeightMeasureSpec);
seekBarWidth = seekBar.getMeasuredWidth();
seekBarHeight = seekBar.getMeasuredHeight();
}
final int measuredWidth = ViewCompat.resolveSizeAndState(seekBarWidth + hPadding, widthMeasureSpec, 0);
final int measureHeight = ViewCompat.resolveSizeAndState(seekBarHeight + vPadding, heightMeasureSpec, 0);
setMeasuredDimension(measuredWidth, measureHeight);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
private void applyViewRotation(int w, int h) {
final MySeekBar seekBar = getChildSeekBar();
if (seekBar != null) {
final boolean isLTR = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_LTR;
final int rotationAngle = seekBar.getRotationAngle();
final int seekBarMeasuredWidth = seekBar.getMeasuredWidth();
final int seekBarMeasureHeight = seekBar.getMeasuredHeight();
final int hPadding = getPaddingLeft() + getPaddingRight();
final int vPadding = getPaddingTop() + getPaddingBottom();
final float hOffset = (Math.max(0, w - hPadding) - seekBarMeasureHeight) * 0.5f;
final ViewGroup.LayoutParams lp = seekBar.getLayoutParams();
lp.width = Math.max(0, h - vPadding);
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
seekBar.setLayoutParams(lp);
seekBar.setPivotX((isLTR) ? 0 : Math.max(0, h - vPadding));
seekBar.setPivotY(0);
switch (rotationAngle) {
case VerticalSeekBar.ROTATION_ANGLE_CW_90:
seekBar.setRotation(90);
if (isLTR) {
seekBar.setTranslationX(seekBarMeasureHeight + hOffset);//见图 为何要平移这么多
seekBar.setTranslationY(0);
} else {
ViewCompat.setTranslationX(seekBar, -hOffset);
ViewCompat.setTranslationY(seekBar, seekBarMeasuredWidth);
}
break;
case VerticalSeekBar.ROTATION_ANGLE_CW_270:
ViewCompat.setRotation(seekBar, 270);
if (isLTR) {
ViewCompat.setTranslationX(seekBar, hOffset);
ViewCompat.setTranslationY(seekBar, seekBarMeasuredWidth);
} else {
ViewCompat.setTranslationX(seekBar, -(seekBarMeasureHeight + hOffset));
ViewCompat.setTranslationY(seekBar, 0);
}
break;
}
}
}
private MySeekBar getChildSeekBar() {
final View child = (getChildCount() > 0) ? getChildAt(0) : null;
return (child instanceof MySeekBar) ? (MySeekBar) child : null;
}
private boolean useViewRotation() {
final MySeekBar seekBar = getChildSeekBar();
if (seekBar != null) {
return seekBar.useViewRotation();
} else {
return false;
}
}
}
选择后为何要平移一个高度单位,如图
克制旋转后需要平移高度的距离。