自定义view实现一个游标效果(增强)
来源:互联网 发布:tcp和udp端口号区别 编辑:程序博客网 时间:2024/06/08 11:11
继上一篇:自定义view实现一个游标效果,在此基础上新增支持功能:
当手指点击某个时间域时,也可以触发游标滑动到当前点击选择的时间域。
下面贴代码:
package com.baicells.omcserver.view;import android.animation.ValueAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.RectF;import android.graphics.Shader;import android.support.annotation.Nullable;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewParent;import com.baicells.omcserver.R;import java.util.ArrayList;public class CursorView extends View { private int width; private int height; private int radius; private int strokeWidth; private int curTextColor; private int inCurTextColor; private ArrayList<String> cursorText; private Paint borderPaint; private Paint innerBgPaint; private Paint textPaint; private int current; private float offsetX; private RectF currentRectF; private boolean isInCurrent; private GestureDetector mDetector; private OnItemSelectListener mListener; public CursorView(Context context) { super(context); } public CursorView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); mDetector = new GestureDetector(context, mGestureListener); borderPaint = new Paint(); borderPaint.setAntiAlias(true); borderPaint.setStyle(Paint.Style.FILL.STROKE); innerBgPaint = new Paint(); innerBgPaint.setAntiAlias(true); innerBgPaint.setStyle(Paint.Style.FILL_AND_STROKE); textPaint = new Paint(); textPaint.setAntiAlias(true); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CursorView); int indexCount = typedArray.getIndexCount(); for (int i = 0; i < indexCount; i++) { int index = typedArray.getIndex(i); switch (index) { case R.styleable.CursorView_current_bg_color: innerBgPaint.setColor(typedArray.getColor(index, Color.GREEN)); break; case R.styleable.CursorView_current_text_color: curTextColor = typedArray.getColor(index, Color.WHITE); break; case R.styleable.CursorView_incurrent_text_color: inCurTextColor = typedArray.getColor(index, Color.BLACK); break; case R.styleable.CursorView_stroke_color: borderPaint.setColor(typedArray.getColor(index, Color.RED)); break; case R.styleable.CursorView_textsize: textPaint.setTextSize(typedArray.getDimensionPixelSize(index, 20)); break; case R.styleable.CursorView_stroke_width: strokeWidth = typedArray.getDimensionPixelSize(index, 3); break; } } typedArray.recycle(); borderPaint.setStrokeWidth(strokeWidth); setLayerType(LAYER_TYPE_SOFTWARE, null); } public CursorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setOnItemSelectListener(OnItemSelectListener listener) { this.mListener = listener; } public void setCursorText(ArrayList<String> cursorText) { this.cursorText = cursorText; invalidate(); } public void setCurrent(int current) { this.current = current; invalidate(); } public int getCurrent() { return current; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); width = 300; height = 20; if (modeWidth == MeasureSpec.EXACTLY) { width = sizeWidth; } if (modeHeight == MeasureSpec.EXACTLY) { height = sizeHeight; } setMeasuredDimension(width, height); radius = height / 2; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //画整个大背景 RectF rect = new RectF(strokeWidth / 2, strokeWidth / 2, width - strokeWidth / 2, height - strokeWidth / 2); canvas.drawRoundRect(rect, radius, radius, borderPaint); if (cursorText != null) { int size = cursorText.size(); float everyWidth = width * 1.0f / size; //画当前选中时间维度的背景 RectF currBgRectF = getCurrBgRectF(everyWidth); currentRectF = currBgRectF; canvas.drawRoundRect(currBgRectF, radius, radius, innerBgPaint); //循环画时间维度文本 for (int i = 0; i < size; i++) { textPaint.setShader(null); String text = cursorText.get(i); Paint.FontMetricsInt metricsInt = textPaint.getFontMetricsInt(); float textwidth = textPaint.measureText(text); float preblank = (everyWidth - textwidth) / 2.0f; float x = everyWidth * i + preblank; float y = (height - metricsInt.bottom + metricsInt.top) / 2.0f - metricsInt.top; if (currBgRectF.left >= x && currBgRectF.left <= x + textwidth) { float split = (currBgRectF.left - x) / textwidth; LinearGradient shader = new LinearGradient(x, 0, x + textwidth, 0, new int[]{inCurTextColor, curTextColor}, new float[]{ split, split + 0.01f}, Shader.TileMode.CLAMP); textPaint.setShader(shader); } if (currBgRectF.right >= x && currBgRectF.right <= x + textwidth) { float split = (currBgRectF.right - x) / textwidth; LinearGradient shader = new LinearGradient(x, 0, x + textwidth, 0, new int[]{curTextColor, inCurTextColor}, new float[]{ split, split + 0.01f}, Shader.TileMode.CLAMP); textPaint.setShader(shader); } if (currBgRectF.left < x && currBgRectF.right > x + textwidth) { textPaint.setColor(curTextColor); } else { textPaint.setColor(inCurTextColor); } canvas.drawText(text, x, y, textPaint); } } } private RectF getCurrBgRectF(float everyWidth) { float left = everyWidth * current + offsetX; float right = everyWidth * (current + 1) + offsetX; if (left < 0) { left = 0; right = everyWidth; } if (right > width) { left = width - everyWidth; right = width; } return new RectF(left, 0, right, height); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { ViewParent parent = null; while (true) { if (parent != null && parent instanceof ViewPager) { break; } if (parent != null) { parent = parent.getParent(); } else { parent = getParent(); } } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: parent.requestDisallowInterceptTouchEvent(true); break; default: parent.requestDisallowInterceptTouchEvent(false); break; } return super.dispatchTouchEvent(ev); } private float downX = 0; private float downY = 0; @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); isInCurrent = currentRectF.contains(downX, downY); break; case MotionEvent.ACTION_MOVE: if (isInCurrent) { offsetX = x - downX; invalidate(); } break; case MotionEvent.ACTION_UP: if (isInCurrent) { final NextCurrent nextCurrent = computeScrollX(currentRectF.left); final float lastX = offsetX; ValueAnimator anim = ValueAnimator.ofFloat(0, nextCurrent.getX()); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); offsetX = lastX + value; invalidate(); float fraction = animation.getAnimatedFraction(); if (fraction == 1.0f) { current = nextCurrent.getIndex(); offsetX = 0; if (mListener != null) { mListener.onItemSelect(nextCurrent.getIndex()); } } } }); anim.setDuration(100); anim.start(); } break; } mDetector.onTouchEvent(event); return true; } private NextCurrent getNeedScroll(float pointX) { if (cursorText != null) { NextCurrent next = new NextCurrent(); int size = cursorText.size(); float everyWidth = width * 1.0f / size; int index = 0; for (int i = 0; i < size; i++) { if (pointX > everyWidth * i && pointX < everyWidth * (i + 1)) { index = i; break; } } next.setIndex(index); next.setX(everyWidth * index - currentRectF.left); return next; } return null; } private NextCurrent computeScrollX(float left) { NextCurrent next = new NextCurrent(); int index = 0; if (cursorText != null) { int size = cursorText.size(); float everyWidth = width * 1.0f / size; float min = everyWidth + 1; for (int i = 0; i < size; i++) { float abs = Math.abs(left - everyWidth * i); if (abs < min) { min = abs; index = i; } } if (everyWidth * index > left) { next.setX(min); } else { next.setX(-min); } next.setIndex(index); } return next; } private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { if (!isInCurrent) { final NextCurrent needScroll = getNeedScroll(e.getX()); ValueAnimator anim = ValueAnimator.ofFloat(0, needScroll.getX()); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { offsetX = (float) animation.getAnimatedValue(); invalidate(); float fraction = animation.getAnimatedFraction(); if (fraction == 1.0f) { current = needScroll.getIndex(); offsetX = 0; if (mListener != null) { mListener.onItemSelect(current); } } } }); anim.setDuration(300); anim.start(); } return super.onSingleTapConfirmed(e); } }; private class NextCurrent { private int index; private float x; public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public float getX() { return x; } public void setX(float x) { this.x = x; } } public interface OnItemSelectListener { void onItemSelect(int item); }}
阅读全文
0 0
- 自定义view实现一个游标效果(增强)
- 自定义view实现一个游标效果
- 自定义view实现一个view的磁贴效果
- Android下 一个自定义VIEW实现简单的弹幕效果
- 初识kotlin实现一个类似烟花效果的自定义view
- 自定义View实现刮刮卡效果
- 自定义View实现SwichButton效果
- 自定义 View 实现钟表效果
- 自定义View实现索引效果
- 自定义view实现炸弹效果
- 自定义view实现水波纹效果(已优化)
- 自定义View实现SeekBar点值选择效果(一)
- 自定义View(四) Graphics2D 实现动态效果
- 自定义View实现点值选择效果(二)
- 实现一个自定义波浪View
- 自定义View实现转盘旋转效果
- 自定义view实现图文环绕的效果
- 自定义view实现水波荡漾的效果
- 如何在 build.gradle 中更整洁,更符合逻辑,更高效的书写代码
- Linux命令
- 反射
- If($i==true)和If(true==$i)区别
- python简单示例
- 自定义view实现一个游标效果(增强)
- JVM线上问题排查
- 关于视频播放
- 存储过程中处理用逗号拼接成的参数
- 深度学习在目标检测中的应用及其tensorflowAPI实践(一)
- 如何使用PDF转换器将PDF转换成图片
- linux nfs 命令
- java中的抽象类和接口
- web 服务器打开gzip压缩