安卓自定义view之——可滑动时间轴(时间刻度尺)
如果需要解决在viewpager,horizontalscrollview中滑动事件的冲突,可注入viewpager,horizontalscrollview对象,在down move的时候调用requestdisallowInterceptDispatch()
好了先看效果图
看代码:自定义view类
package com.example.viewpager;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.Layout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;
public class TimeAxis extends View {
private static final float INTERVAL_LENGTH = 0.08f;// 一小格的长度,单位dp
private static final int BIG_TIME_INTERVAL = 1800;// 30分钟一大格
private static final int SMALL_TIME_INTERVAL = 1;// 1秒钟一小格 ,小刻度线不画
private static final int TICK_MARK_HEIGHT = 50;// 大刻度线高度
private static final int TEXT_SIZE = 12;// 文字大小
private float mDensity;// 屏幕密度 dp*mDensity=px
private TimeAlgorithm mValue;// 当前刻度指示时间
private TimeAlgorithm mMaxValue;// 刻度最大阀值
private TimeAlgorithm mMinValue;// 刻度最小阀值
private float mLastX, mMove;
private float mWidth, mHeight;
private int mMinVelocity;
private Scroller mScroller;
private VelocityTracker mVelocityTracker;
private OnValueChangeListener mListener;
private SQLiteDatabase db = null;
private long st;
private long et;
private String mDate;
private boolean isEnabled;
private MyViewPager vg;
public interface OnValueChangeListener {
public void onValueChange(TimeAlgorithm _value);
public void onStartValueChange(TimeAlgorithm _value);
public void onStopValueChange(TimeAlgorithm _value);
}
public TimeAxis(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
if(isInEditMode())
return;
mScroller = new Scroller(context);
mDensity = context.getResources().getDisplayMetrics().density;
mMinVelocity = ViewConfiguration.get(context)
.getScaledMinimumFlingVelocity();
mMaxValue = new TimeAlgorithm("23:59:59");
mMinValue = new TimeAlgorithm("00:00:00");
Date nowTime = new Date(System.currentTimeMillis());
SimpleDateFormat sdFormatter = new SimpleDateFormat("yyyy-MM-dd");
mDate = sdFormatter.format(nowTime);
sdFormatter = new SimpleDateFormat("HH:mm:ss");
mValue = new TimeAlgorithm(sdFormatter.format(nowTime));
isEnabled = true;
setBackgroundColor(Color.parseColor("#88424242"));
}
public void setVg(MyViewPager _vg)
{
vg=_vg;
}
public void setEnabled(boolean arg) {
isEnabled = arg;
}
public boolean is_Enabled() {
return isEnabled;
}
public void setDate(String _date) {
mDate = _date;
}
public void setDataBase(SQLiteDatabase _db) {
db = _db;
postInvalidate();
}
public void drawVideo(Canvas canvas) {
Paint linePaint = new Paint();
linePaint.setStrokeWidth(1);
Cursor cursor;
RectF r;
if (st < et) {
cursor = db.rawQuery("select * from VideoList where minValue < "
+ et + " and maxValue > " + st, null);
while (cursor.moveToNext()) {
linePaint.setColor(Color.parseColor("#66FF4040"));
r = new RectF((cursor.getLong(1) - st) * INTERVAL_LENGTH
* mDensity, 0, (cursor.getLong(2) - st)
* INTERVAL_LENGTH * mDensity, this.getHeight());
canvas.drawRoundRect(r, 0, 0, linePaint);
linePaint.setColor(Color.parseColor("#88424242"));
canvas.drawLine((cursor.getLong(1) - st) * INTERVAL_LENGTH
* mDensity, 0, (cursor.getLong(1) - st)
* INTERVAL_LENGTH * mDensity, getHeight(), linePaint);
}
} else {
cursor = db.rawQuery(
"select * from VideoList where (minValue < "
+ mMaxValue.getSec(mDate) + " and maxValue > " + st
+ ")" + " or (minValue <" + et + " and maxValue>"
+ mMinValue.getSec(mDate) + ")", null);
while (cursor.moveToNext()) {
if (cursor.getLong(2) >= st) {
linePaint.setColor(Color.parseColor("#66FF4040"));
r = new RectF((cursor.getLong(1) - st) * INTERVAL_LENGTH
* mDensity, 0, (cursor.getLong(2) - st)
* INTERVAL_LENGTH * mDensity, this.getHeight());
canvas.drawRoundRect(r, 0, 0, linePaint);
linePaint.setColor(Color.parseColor("#88424242"));
canvas.drawLine((cursor.getLong(1) - st) * INTERVAL_LENGTH
* mDensity, 0, (cursor.getLong(1) - st)
* INTERVAL_LENGTH * mDensity, getHeight(),
linePaint);
} else {
linePaint.setColor(Color.parseColor("#66FF4040"));
Long value = cursor.getLong(1) - mMinValue.getSec(mDate);
value = value > 0 ? value : 0;
r = new RectF(
(mMaxValue.getSec(mDate) - st + value)
* INTERVAL_LENGTH * mDensity,
0,
((mMaxValue.getSec(mDate) - st) + cursor.getLong(2) - mMinValue
.getSec(mDate))
* INTERVAL_LENGTH
* mDensity, getHeight());
canvas.drawRoundRect(r, 0, 0, linePaint);
linePaint.setColor(Color.parseColor("#88424242"));
canvas.drawLine((mMaxValue.getSec(mDate) - st + value)
* INTERVAL_LENGTH * mDensity, 0,
(mMaxValue.getSec(mDate) - st + value)
* INTERVAL_LENGTH * mDensity, getHeight(),
linePaint);
}
}
}
cursor.close();
cursor = null;
}
public void setOnValueChangeListener(OnValueChangeListener listener) {
mListener = listener;
}
public TimeAlgorithm getValue() {
return mValue;
}
public Long getSec() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
Long sec = 0l;
try {
date = sdf.parse(mDate + " " + mValue.getData());
Calendar calendarObj = Calendar.getInstance();
calendarObj.setTime(date);
sec = calendarObj.getTimeInMillis() / 1000;
return sec;
} catch (ParseException e) {
return sec;
}
}
public void setValue(TimeAlgorithm _value) {
mValue = _value;
int sec = Math.round(mWidth / (2 * INTERVAL_LENGTH * mDensity));
st = mValue.addOrSub(-sec).getSec(mDate);
et = mValue.addOrSub(sec).getSec(mDate);
postInvalidate();
}
public void setValue(Long miliSec) {
Date nowTime = new Date(miliSec);
SimpleDateFormat sdFormatter = new SimpleDateFormat("HH:mm:ss");
mValue = new TimeAlgorithm(sdFormatter.format(nowTime));
int sec = Math.round(mWidth / (2 * INTERVAL_LENGTH * mDensity));
st = mValue.addOrSub(-sec).getSec(mDate);
et = mValue.addOrSub(sec).getSec(mDate);
postInvalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
mWidth = getWidth();
mHeight = getHeight();
int sec = Math.round(mWidth / (2 * INTERVAL_LENGTH * mDensity));
st = mValue.addOrSub(-sec).getSec(mDate);
et = mValue.addOrSub(sec).getSec(mDate);
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
try {
if (db != null) {
drawVideo(canvas);
}
drawScaleLine(canvas);
drawMiddleLine(canvas);
} catch (ParseException e) {
}
}
private void drawScaleLine(Canvas canvas) throws ParseException {
canvas.save();
Paint linePaint = new Paint();
linePaint.setStrokeWidth(2);
linePaint.setColor(Color.rgb(255, 0, 0));
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.rgb(255, 255, 0));
textPaint.setTextSize(TEXT_SIZE * mDensity * 0.7f);
float xPosition = 0, textWidth = Layout.getDesiredWidth("0", textPaint);
int numSize = String.valueOf("00:00:00").length();
int mod = mValue.mod(BIG_TIME_INTERVAL);
if (mod < BIG_TIME_INTERVAL / 2)
canvas.drawText(String.valueOf(mValue.getData()), mWidth / 2 + 6,
getHeight() / 2, textPaint);
else
canvas.drawText(String.valueOf(mValue.getData()), mWidth / 2
- numSize * textWidth, getHeight() / 2, textPaint);
textPaint.setTextSize(TEXT_SIZE * mDensity);
textPaint.setColor(Color.rgb(255, 0, 0));
float drawCount = 0;
for (int i = 0; drawCount < mWidth; i++) {
xPosition = (mWidth / 2 - mMove) + ((1800 - mod) + 1800 * i)
* INTERVAL_LENGTH * mDensity;
if (xPosition + getPaddingRight() < mWidth) {
canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity
* TICK_MARK_HEIGHT, linePaint);
canvas.drawText(
String.valueOf(mValue.addOrSub(
SMALL_TIME_INTERVAL * i * 1800 + 1800 - mod)
.getData()), xPosition - (textWidth * numSize)
/ 2, getHeight() - textWidth, textPaint);
}
xPosition = (mWidth / 2 - mMove) - (mod + 1800 * i)
* INTERVAL_LENGTH * mDensity;
if (xPosition > getPaddingLeft()) {
canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity
* TICK_MARK_HEIGHT, linePaint);
canvas.drawText(String.valueOf(mValue.addOrSub(
-SMALL_TIME_INTERVAL * 1800 * i - mod).getData()),
xPosition - (textWidth * numSize) / 2, getHeight()
- textWidth, textPaint);
}
drawCount += 2 * INTERVAL_LENGTH * mDensity * 1800;
}
canvas.restore();
}
private void drawMiddleLine(Canvas canvas) {
// int gap = 12, shadow = 6;
// String color = "#66999999";
// int indexWidth = 2, indexTitleWidth = 24, indexTitleHight = 10;
canvas.save();
Paint redPaint = new Paint();
redPaint.setStrokeWidth(2);
redPaint.setColor(Color.rgb(255, 255, 0));
canvas.drawLine(mWidth / 2, 0, mWidth / 2, mHeight, redPaint);
Paint ovalPaint = new Paint();
ovalPaint.setColor(Color.rgb(255, 255, 0));
ovalPaint.setStrokeWidth(24);
canvas.drawLine(mWidth / 2, 0, mWidth / 2, 10, ovalPaint);
canvas.drawLine(mWidth / 2, mHeight - 10, mWidth / 2, mHeight,
ovalPaint);
// Paint shadowPaint = new Paint();
// shadowPaint.setStrokeWidth(shadow);
// shadowPaint.setColor(Color.parseColor(color));
// canvas.drawLine(mWidth / 2 + gap, 0, mWidth / 2 + gap, mHeight,
// shadowPaint);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
float xPosition = event.getX();
if (mVelocityTracker == null)
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.e("()()", "ti onTouchEvent down*****************");
vg.requestDisallowInterceptTouchEvent(true);
mListener.onStartValueChange(mValue);
mScroller.forceFinished(true);
mLastX = xPosition;
mMove = 0;
return true;
case MotionEvent.ACTION_MOVE:
Log.e("()()", "ti onTouchEvent move*****************");
vg.requestDisallowInterceptTouchEvent(true);
mMove += (mLastX - xPosition);
changeMoveAndValue();
break;
case MotionEvent.ACTION_UP:
Log.e("()()", "ti onTouchEvent up*****************");
case MotionEvent.ACTION_CANCEL:
Log.e("()()", "ti onTouchEvent cancle*****************");
vg.requestDisallowInterceptTouchEvent(false);
countVelocityTracker(event);
countMoveEnd();
break;
// return false;
default:
break;
}
mLastX = xPosition;
return super.onTouchEvent(event);
}
// 松开手控件滑动起来,fling()需要postInvalidate()
private void countVelocityTracker(MotionEvent event) {
mVelocityTracker.computeCurrentVelocity(1000, 1000);
float xVelocity = mVelocityTracker.getXVelocity();
if (Math.abs(xVelocity) > mMinVelocity)
mScroller.fling(0, 0, (int) xVelocity, 0, Integer.MIN_VALUE,
Integer.MAX_VALUE, 0, 0);
else
if(isEnabled)
mListener.onStopValueChange(mValue);
}
private void changeMoveAndValue() {
float tValue = mMove / (INTERVAL_LENGTH * mDensity);
if (Math.abs(tValue) > 0) {
mValue = mValue.addOrSub(Math.round(tValue * SMALL_TIME_INTERVAL));
int sec = Math.round(mWidth / (2 * INTERVAL_LENGTH * mDensity));
st = mValue.addOrSub(-sec).getSec(mDate);
et = mValue.addOrSub(sec).getSec(mDate);
mMove -= tValue * INTERVAL_LENGTH * mDensity;
notifyValueChange();
}
postInvalidate();
}
private void notifyValueChange() {
if (null != mListener)
if (mScroller.isFinished())
mListener.onValueChange(mValue);
}
private void countMoveEnd() {
float roundMove = mMove / (INTERVAL_LENGTH * mDensity);
if (Math.abs(roundMove) > 0) {
mValue = mValue.addOrSub(Math
.round(roundMove * SMALL_TIME_INTERVAL));
int sec = Math.round(mWidth / (2 * INTERVAL_LENGTH * mDensity));
st = mValue.addOrSub(-sec).getSec(mDate);
et = mValue.addOrSub(sec).getSec(mDate);
}
mLastX = 0;
mMove = 0;
notifyValueChange();
postInvalidate();
}
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
if (mScroller.getCurrX() == mScroller.getFinalX()) {
countMoveEnd();
if(isEnabled)
mListener.onStopValueChange(mValue);
} else {
int xPosition = mScroller.getCurrX();
mMove += (mLastX - xPosition);
changeMoveAndValue();
mLastX = xPosition;
}
}
}
}
运算类:
package com.example.viewpager;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class TimeAlgorithm {
private String mTime;
public TimeAlgorithm(String _mTime) {
// TODO Auto-generated constructor stub
mTime = _mTime;
}
// 加上或减去_sec秒
public TimeAlgorithm addOrSub(int _sec) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = sdf.parse("2015-07-07 " + mTime);
Calendar calendarObj = Calendar.getInstance();
calendarObj.setTime(date);
calendarObj.add(Calendar.SECOND, _sec);
SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss");
TimeAlgorithm mt = new TimeAlgorithm(sdf2.format(calendarObj
.getTime()));
return mt;
} catch (ParseException e) {
return null;
}
}
public int mod(int _timeInterval) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
try {
date = sdf.parse("2015-07-07 " + mTime);
Calendar calendarObj = Calendar.getInstance(Locale.CHINA);
calendarObj.setTime(date);
int m = calendarObj.get(Calendar.MINUTE);
int s = calendarObj.get(Calendar.SECOND);
return (60 * m + s) % _timeInterval;
} catch (ParseException e) {
return -1;
}
}
public long compareTime(TimeAlgorithm _mt) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
try {
date = sdf.parse("2015-07-07 " + mTime);
Calendar calendarObj = Calendar.getInstance();
calendarObj.setTime(date);
Long d = calendarObj.getTimeInMillis();
date = sdf.parse("2015-07-07 " + _mt.mTime);
calendarObj.setTime(date);
Long _d = calendarObj.getTimeInMillis();
return d - _d;
} catch (ParseException e) {
return 111111;
}
}
public String getData() {
return mTime;
}
public long getSec(String _date)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
try {
date = sdf.parse(_date+" " + mTime);
Calendar calendarObj = Calendar.getInstance();
calendarObj.setTime(date);
Long d=calendarObj.getTimeInMillis()/1000;
return d ;
} catch (ParseException e) {
return -1;
}
}
}
安卓自定义view之——可滑动时间轴(时间刻度尺)相关推荐
- 安卓自定义View——网易颜色渐变效果指示器
一直想写博客来着,可惜直到现在才真正抽出时间.最近一直在研究网易新闻这个UI框架,发现了一些很值得借鉴的效果,当然,网上也不乏这方面的介绍.本文主要实现的指示器效果为字体颜色和大小渐变,废话不多说献上 ...
- 安卓自定义View进阶-事件分发机制原理
之前讲解了很多与View绘图相关的知识,你可以在 安卓自定义View教程目录 中查看到这些文章,如果你理解了这些文章,那么至少2D绘图部分不是难题了,大部分的需求都能满足,但是关于View还有很多知识 ...
- android 自定义view滚动条,Android自定义View实现等级滑动条的实例
Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候 ...
- 安卓自定义view中 绘画基本图形点线面,矩形,方形,圆,扇形,文字及沿着特定方向布局,自定义圆角ImageView图片等等相关api使用方法及举例
安卓自定义view中 绘画基本图形点线面,矩形,方形,圆,扇形,文字及沿着特定方向布局,自定义圆角ImageView图片等等相关api使用方法及举例,图片压缩处理逻辑 本文旨在介绍自定义View的实现 ...
- android控件向内弧度_安卓自定义 View 基础:坐标系、角度弧度、颜色
安卓自定义View基础 - 坐标系 一.屏幕坐标系和数学坐标系的区别 由于移动设备一般定义屏幕左上角为坐标原点,向右为x轴增大方向,向下为y轴增大方向, 所以在手机屏幕上的坐标系与数学中常见的坐标系是 ...
- 安卓自定义View实现加载gif图片
开题:加载GIF的场景在安卓开发中还比较常见,网上也有一些三方法的框架会支持对gif的加载,在上篇博客为大家推荐的图片加载库Glide也支持gif的加载Glide工具类的简单封装,今天给大家分享通过自 ...
- 安卓自定义view全解:初始化,onDraw函数,onMeasure函数,用户手势事件
全栈工程师开发手册 (作者:栾鹏) 安卓教程全解 安卓自定义view全解. view类包含如下函数.可供重写. onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后 ...
- 安卓自定义View的状态保存与恢复
安卓自定义View的状态保存与恢复 我们在开发某些安卓应用(如安卓小游戏)时,可能会用到自定义View,这时候往往需要保存自定义View的状态信息,以便在遇到某些情况(如由于系统内存资源紧张被系统杀死 ...
- uniapp、vue实现时间轴和刻度尺显示相关行程
uniapp.vue实现时间轴和刻度尺显示相关行程 <template><view class="time-line"><block v-for=&q ...
最新文章
- 全国知名高校网站挂马现象严重 考生面临安全风险
- Java并发编程(5):volatile变量修饰符—意料之外的问题(含代码)
- pytorch torch.Tensor.clone()(返回张量自身的副本。 副本具有与自身相同的大小和数据类型。)
- python中的引用怎么理解_Python函数通过引用调用
- 官网mysql安装目录_官网下载MySQL 并安装
- JAVA反射系列之Field,java.lang.reflect.Field使用获取方法。
- 现身说法“好奇心害死人啊”
- OceanBase杨传辉:一体化架构的分布式数据库已成为企业级系统首选
- spring boot之security
- 四年级下册英语计算机房和教师办公室的图片,人教版四年级英语下册Unit 1单元知识梳理卷...
- 【Flutter】微信项目实战【02】我的界面搭建(上)
- LogServer日志详解
- 计算机类教育部科目分类,教育部学科门类及一的级学科目录表.doc
- NYOJ 366 (全排列)
- java jar 启动好慢_Tomcat启动很慢,提示“At least one JAR was scanned for TLDs yet contained no TLDs.”...
- 二面深信服前端,秋招面经分享
- synology nfs_如何手动和自动关闭和重新启动Synology NAS
- mysql错误42000_mysql5.7 异常ERROR 1055 (42000)
- 浅析疯狂动物城的制作流程
- CDN,高防IP接入报错504是为什么。解答方案一。