HorizontalNumberView與seekbar共享滑動的自定義view
阿新 • • 發佈:2019-02-20
這是一個簡單的,能與seekbar共享滑動的自定義view
我的部落格:詳解
簡單分析:
- 初始化一些引數,設定資料,準備在onDraw方法中連續繪製TextView
- 計算出TextView繪製的座標點,根據左滑還是右滑設定TextView之間間隙,大小,顏色
- 將seekbar注入進來,根據對調監聽設定當前位置,進行重繪,繪製最新的陣列列表
實現難點:
- 計算出繪製陣列寬度與高度
- TextView繪製座標與方式
- seekbar回撥,改變哪一些值可以達到預期的滑動效果
- 往左滑計算方式,往右滑計算方式
- 設定不同狀態下TextViewde引數
自定義View分析:
HorizontalNumberView
- 首先,初始化構造器與必要引數
public class HorizontalNumberView extends View implements SeekBar.OnSeekBarChangeListener {
private static final int SPACE_NUM = 2;
private static String[] NUMBERS = new String[] {
"1", "2", "3", "4", "5", "6", "7" , "8", "9", "10"
};
private static int mNormalTextColor;
private static int mSelectTextColor;
private int mNormalTextSize = 32;
private int mSelectTextSize = 60;
private int mNumberMax;
private SeekBar mSeekBar;
private int mItemHeight;
private int mItemWidth;
private int mOffset;
private int mCurrentProgress = 0;
private int mBeforeProgress = 0;
private int mCurrentIndex = 1;
private double mCurrentValue;
private Paint mPaint;
private Paint mSelectPaint;
private Rect mBounds;
private OnSeekBarChangeListener mOnSeekBarChangeListener;
public HorizontalNumberView(Context context) {
this(context, null);
}
public HorizontalNumberView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HorizontalNumberView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mNumberMax = NUMBERS.length + SPACE_NUM;
mNormalTextColor = getResources().getColor(R.color.number_view_normal_text_color);
mSelectTextColor = getResources().getColor(R.color.number_view_select_text_color);
//init text paint
mPaint = new Paint();
mPaint.setColor(mNormalTextColor);
mPaint.setAntiAlias(true);
mPaint.setTextSize(mNormalTextSize);
//init color paint
mSelectPaint = new Paint();
mSelectPaint.setColor(mSelectTextColor);
mSelectPaint.setAntiAlias(true);
mSelectPaint.setTextSize(mSelectTextSize);
//init text bound rect
mBounds = new Rect();
}
- 獲取PullRelativeLayoutState的狀態值,根據它來判斷是否處理事件:自己處理,子View處理,不處理等
- OnScrollStateChangeListener把ScrollView滾動高度狀態回調出去,給外面使用
HeaderFrameLayout
public class HeaderFrameLayout extends FrameLayout {
private Scroller mScroller;
private int mHeight;
private boolean isOpen;
public HeaderFrameLayout(Context context) {
super(context);
init();
}
public HeaderFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HeaderFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mScroller = new Scroller(getContext());
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mHeight = getMeasuredHeight();
}
public void setOpen(boolean flag) {
isOpen = flag;
}
public boolean isOpen() {
return isOpen;
}
public void open() {
if (!isOpen) {
return;
}
smoothScrollTo(0, mHeight, 0, -mHeight, 800);
isOpen = false;
}
private void smoothScrollTo(int startX, int startY,
int dx, int dy, int duration) {
mScroller.startScroll(startX, startY, dx, dy, duration);
invalidate();
}
}
- 計算TextView寬高,注入seekbar設定監聽,設定必要引數
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//init text width and height
mItemHeight = getMeasuredHeight();
mItemWidth = getMeasuredWidth() / mNumberMax;
//check set seek bar
if (mSeekBar == null) {
throw new RuntimeException("you must call set seekBar method!");
}
mSeekBar.setOnSeekBarChangeListener(this);
}
public void setSeekBar(SeekBar seekBar) {
mSeekBar = seekBar;
mSeekBar.setMax((NUMBERS.length - 1) * 10);//set seekBar max value
}
@Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mCurrentProgress = progress;
mCurrentIndex = (mCurrentProgress / NUMBERS.length) + 1;
mCurrentValue = mCurrentIndex + ((mCurrentProgress % 10) / 10.0f);
invalidate();
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
mOnSeekBarChangeListener.onStateChangeBack(mCurrentProgress, mCurrentIndex,
getCurrentValue());
}
}
- onDraw方法中根據左滑還是右滑設定TextView距離,即實際的位置
@Override protected void onDraw(Canvas canvas) {
//start draw text
for (int i = 0; i < NUMBERS.length; i++) {
String text = NUMBERS[i];
int textIndex = i + 1;
if (mCurrentProgress > 0 && mCurrentProgress > mBeforeProgress) {//left to right slip
//item % value
float value = (mCurrentProgress % 10) / 10.0f;
if (textIndex - mCurrentIndex == 0) {//current text
mOffset = (int) (mOffset + mItemWidth - value * mItemWidth);
}
if (textIndex - mCurrentIndex == 1) {//current+1
mOffset += mItemWidth;
}
if (textIndex - mCurrentIndex == 2) {//current+2
mOffset = (int) (mOffset + value * mItemWidth);
}
} else if (mCurrentProgress > 0 && mCurrentProgress < mBeforeProgress) {//right to left slip
//item % value
float value = 1 - ((mCurrentProgress % 10) / 10.0f);
if (textIndex - mCurrentIndex == 0 && mCurrentIndex != 1) {//current text
mOffset += mItemWidth;
}
if (textIndex - mCurrentIndex == -1) {//current - 1
mOffset = (int) (mOffset + value * mItemWidth);
}
if (textIndex - mCurrentIndex == 1 && mCurrentIndex != 1) {//current + 1
mOffset = (int) (mOffset + mItemWidth - value * mItemWidth);
}
}
//text width
int textX = (int) (mItemWidth * 0.5f + i * mItemWidth + mOffset);
mPaint.getTextBounds(text, 0, text.length(), mBounds);
//text height
float textHeight = mBounds.height();
int textY = (int) (mItemHeight * 0.5f + textHeight * 0.5f);
float fontHeight = mPaint.getFontMetrics().bottom - mPaint.getFontMetrics().top;
float posValue = fontHeight / 2 - mPaint.getFontMetrics().descent - 10;
//text draw
if (textIndex == mCurrentIndex) {
canvas.drawText(text, textX, textY + posValue, mSelectPaint);
} else {
canvas.drawText(text, textX, textY + posValue, mPaint);
}
}
//reset params
mOffset = 0;
mBeforeProgress = mCurrentProgress;
}
onDraw方法為核心內容,必要的地方都有註釋,實現方式可能有很多種,分析就到這裡。
再來看一次效果圖:
10/31/2016 12:49:08 AM