项目中用到自定义尺子的样式:

原代码在github上找的,地址:https://github.com/QQabby/HorizontalRuler

原效果为

因为跟自己要使用的view稍有不同 所以做了一些修改,修改的注释都放在代码中了,特此记录一下。

首先是一个自定义View:

public class RuleView extends View {

private Paint paint;

private Context context;

private int maxValue = 500;

/**

* 起点x的坐标

*/

private float startX ;

private float startY ;

/**

* 刻度线的长度

*/

private float yLenght ;

/**

* 刻度的间隙

*/

// private float gap = 8f;

private float gap = 10;

/**

* 文本的间隙

*/

private float textGap = 10f;

/**

* 短竖线的高度

*/

private float smallHeight = 10f;

/**

* 长竖线的高度

*/

private float largeHeight = 22f;

/**

* 文本显示格式化

*/

private DecimalFormat format;

private DisplayMetrics metrics = null;

/**

* 文本的字体大小

*/

private float mFontSize;

private Handler mScrollHandler = null;

private MyHorizontalScrollView horizontalScrollView;

private int mCurrentX = -999999999;

/**

* 刻度进制

*/

// private float unit = 10f;

private int unit = 10;//隔unit个刻度写一个数字

//每个大刻度代表值iValue

private int iValue = 10;

boolean isDraw = true;

public RuleView(Context context) {

super(context);

this.context = context;

init();

}

public void setHorizontalScrollView(

MyHorizontalScrollView horizontalScrollView) {

this.horizontalScrollView = horizontalScrollView;

this.horizontalScrollView.setOnTouchListener(new OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

final int action = event.getAction();

switch (action) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

mScrollHandler.removeCallbacks(mScrollRunnable);

break;

case MotionEvent.ACTION_UP:

mScrollHandler.post(mScrollRunnable);

break;

}

return false;

}

});

}

public RuleView(Context context, AttributeSet attrs) {

super(context, attrs);

this.context = context;

init();

}

public void init() {

// format = new DecimalFormat("0.0");

format = new DecimalFormat("0");//不使用浮点数格式

metrics = new DisplayMetrics();

WindowManager wmg = (WindowManager) context

.getSystemService(Context.WINDOW_SERVICE);

wmg.getDefaultDisplay().getMetrics(metrics);

paint = new Paint(Paint.ANTI_ALIAS_FLAG);

paint.setStyle(Paint.Style.FILL);

paint.setStrokeWidth(getResources().getDimension(R.dimen.ui_1_dip));

// paint.setStrokeWidth(2);

paint.setColor(Color.parseColor("#999999"));

mFontSize = ScreenUtil.dip2px(context, 16);

// startY = ScreenUtil.dip2px(context, 20f);

startY = ScreenUtil.dip2px(context, 0);//Y轴由0开始,即最顶端,不用设置适配布局文件RuleView的android:layout_marginTop="-20dp"

yLenght = ScreenUtil.dip2px(context, 10);

// gap = ScreenUtil.dip2px(context, 8f);

gap = ScreenUtil.dip2px(context, 10);

// startX = ScreenUtil.getScreenWidth(context)/ 2.0f- getResources().getDimension(R.dimen.ui_10_dip) ;

startX = ScreenUtil.getScreenWidth(context)/ 2.0f;//X轴不减去10dp,则三角形顶点可以刚好最准0位置

// + getResources().getDimension(R.dimen.text_h2)/2.0f

// Util.dip2px(context, 13f) +

mScrollHandler = new Handler(context.getMainLooper());

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

float width = maxValue * gap + ScreenUtil.getScreenWidth(context) - getResources().getDimension(R.dimen.ui_10_dip)*2.0f ;

// int widthMode = MeasureSpec.getMode(heightMeasureSpec);

// if(widthMode == MeasureSpec.AT_MOST){

// Log.d("TAG", "mode::AT_MOST");

// }else if(widthMode == MeasureSpec.EXACTLY){

// Log.d("TAG", "mode::EXACTLY");

// }else if(widthMode == MeasureSpec.UNSPECIFIED){

// Log.d("TAG", "mode::UNSPECIFIED");

// }

setMeasuredDimension((int) width, heightMeasureSpec);

}

@Override

protected void onDraw(final Canvas canvas) {

super.onDraw(canvas);

// 画刻度线

paint.setColor(getResources().getColor(R.color.gray_bg_high));// 刻度颜色

for (int i = 0; i <= maxValue; i++) {

if (i % 5 == 0) {

yLenght = ScreenUtil.dip2px(context, largeHeight);

} else {

yLenght = ScreenUtil.dip2px(context, smallHeight);

}

canvas.drawLine(i * gap + startX, startY, i * gap + startX, yLenght

+ startY, paint);

}

paint.setTextSize(mFontSize);

// 每10个刻度写一个数字

textGap = gap * unit;

// 画刻度文字30

paint.setColor(getResources().getColor(R.color.textGray));// 文字颜色

for (int i = 0; i <= maxValue / unit; i++) {

// String text = format.format(i + 1) + "";//从0开始计数时不用加1

String text = format.format(i * iValue) + "";//乘以每刻度的值iValue

// 获取文本的宽度

float width = ScreenUtil.px2dip(context, calculateTextWidth(text)) / 2f;

canvas.drawText(

text,

startX - width + i * textGap,

(startY + ScreenUtil.dip2px(context, largeHeight))

+ ScreenUtil.dip2px(context, 24), paint);//字体大小

}

}

/**

* 获取TextView中文本的宽度

*/

private float calculateTextWidth(String text) {

if (TextUtils.isEmpty(text)) {

return 0;

}

TextPaint textPaint = new TextPaint();

textPaint.setTextSize(mFontSize * metrics.scaledDensity);

final float textWidth = textPaint.measureText(text);

return textWidth;

}

DecimalFormat df = new DecimalFormat("0.0");

/**

* 当滑动尺子的时候

*/

int scrollWidth = 0;

public void setScrollerChanaged(int l, int t, int oldl, int oldt) {

// 滑动的距离

scrollWidth = l;

float number = scrollWidth / gap;

float result = number / unit;

listener.onSlide(result);

}

public onChangedListener listener;

public interface onChangedListener {

void onSlide(float number);

}

public void onChangedListener(onChangedListener listener) {

this.listener = listener;

}

/**

* 滚动监听线程

*/

private Runnable mScrollRunnable = new Runnable() {

@Override

public void run() {

if (mCurrentX == horizontalScrollView.getScrollX()) {// 滚动停止了

try {

float x = horizontalScrollView.getScrollX();

float value = (x / (gap * unit));// 当前的值

String s = df.format(value);

// 滑动到11.0 ok

int scrollX = (int) (Double.parseDouble(s) * gap * unit);

horizontalScrollView.smoothScrollTo(scrollX, 0);

} catch (NumberFormatException numExp) {

numExp.printStackTrace();

}

mScrollHandler.removeCallbacks(this);

} else {

mCurrentX = horizontalScrollView.getScrollX();

mScrollHandler.postDelayed(this, 50);

}

}

};

/**

* 设置默认刻度尺的刻度值,不会滚动到相应的位置

*

* @param scaleValue

*/

public void setDefaultScaleValue(float scaleValue) {

// final int scrollX = (int) ((scaleValue - 1.0f) * gap * unit);//从0开始计数时不用减去1

final int scrollX = (int) (scaleValue * gap * unit / 10);//每个值在设置刻度时会乘以10,所以除去

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

horizontalScrollView.smoothScrollTo(scrollX, 0);

}

}, 100);

}

/**

* 设置刻度值

*/

public void setScaleValue(int iValue) {

this.iValue = iValue;

}

/**

* 设置刻度最小值

*/

public void setMinScaleValue(Float minScaleValue) {

// this.minScaleValue = minScaleValue;

}

/**

* 获取刻度最大值

*/

public Float getMaxScaleValue() {

// return maxScaleValue;

return 33.0f;

}

/**

* 设置刻度最大值

*/

public void setMaxScaleValue(Float maxScaleValue) {

// this.maxScaleValue = maxScaleValue;

}

/**

* 设置当前刻度尺的刻度值,并滚动到相应的位置

*

* @param scaleValue

*/

public void setScaleScroll(float scaleValue) {

int scrollX = (int) ((scaleValue - 1.0f) * gap * unit);

horizontalScrollView.smoothScrollTo(scrollX, 0);

}

}

android ui 开发界面量具 尺子,android尺子的自定义view——RulerView详解相关推荐

  1. android标尺自定义view,android尺子的自定义view——RulerView详解

    项目中用到自定义尺子的样式: 原效果为 因为跟自己要使用的view稍有不同 所以做了一些修改,修改的注释都放在代码中了,特此记录一下. 首先是一个自定义View: public class RuleV ...

  2. 【Android游戏开发十二】(保存游戏数据 [上文])详解SharedPreference 与 FIleInputStream/FileOutputStream将数据存储到SD卡中!

     李华明Himi 原创,转载务必在明显处注明: 转载自 [黑米GameDev街区] 原文链接:  http://www.himigame.com/android-game/327.html 很多童鞋说 ...

  3. Android简单登录界面,保存账号和密码(基础,详解)

    一 问题描述: 制作一个简单的登录界面,并使用文件储存方式储存用户名和密码,在下次打开应用时自动获取上次储存的账户和密码 二 解题思路: 文件储存: 文件存储是Android中最基本的一种数据存储方式 ...

  4. android 单选框 icon,Android中的普通对话框、单选对话框、多选对话框、带Icon的对话框、以及自定义Adapter和自定义View对话框详解...

    标签: 对话框就是一个AlertDialog,但是一个简单的AlertDialog,我们却可以将它玩出许多花样来,下面我们就来一起总结一下AlertDialog的用法.看看各位童鞋在平时的工作中否都用 ...

  5. Android自定义View构造函数详解

    转自:http://blog.csdn.net/wzy_1988/article/details/49619773 目录 目录 初始Custom View的构造函数 生成Custom View的自定义 ...

  6. Android UI开发第三十篇——使用Fragment构建灵活的桌面

    http://www.lupaworld.com/article-222973-1.html 当我们设计应用程序时,希望能够尽最大限度的适配各种设备,包括4寸屏.7寸屏. 10寸屏等等,Android ...

  7. 【ANDROID游戏开发十六】ANDROID GESTURE之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/337.html - ...

  8. Android UI开发第四十一篇——墨迹天气3.0引导界面及动画实现

    周末升级了墨迹天气,看着引导界面做的不错,模仿一下,可能与原作者的代码实现不一样,但是实现的效果还是差不多的.先分享一篇以前的文章,android动画的基础知识,<Android UI开发第十二 ...

  9. Android UI开发第三十九篇——Tab界面实现汇总及比较

    Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇--ActivityGroup实现tab功能>.这 ...

  10. Android 开发 -- 开发第一个安卓程序、Android UI开发(布局的创建:相对布局和线性布局、控件单位:px pt dp sp、常用控件 、常见对话框、ListView)

    文章目录 1. 开发第一个Hello World程序 1.1 开发程序 1.2 认识程序中的文件 1.3 Android程序结构 1.4 安卓程序打包 2. Android UI开发 2.1 布局的创 ...

最新文章

  1. VIT自适应语音转文本可预测长度和内容(ocr也可)
  2. FactoryMethod工厂方法模式升级成AbstractFactory抽象工厂模式
  3. delphi 执行一个外部程序,当外部程序结束后言主程序立即响应
  4. 重装了java然后说找不到路径,Java第三次作业第五题
  5. C++数组与指针概念
  6. 【SpringBoot 2】(四)详析SpringBoot的常用注解
  7. TwentyEleven暗色系主题实现透明
  8. InnoDB文件系统
  9. HDU2028 Lowest Common Multiple Plus【GCD+LCM】
  10. MCU——JLINk找不到芯片错误记录
  11. 全新We7 CMS 2.6版火热发布
  12. JavaScript中清空数组的三种方式
  13. 路由器刷机教程图解_小米路由器刷机教程
  14. 操作系统工具推荐 msicuu.exe
  15. 八款最佳的远程桌面工具
  16. Matlab 生成方波信号
  17. 提高代码质量的那些建议
  18. font-awesome样式只显示方框
  19. percona toolkit系列(gh-ost)
  20. matlab 函数 平移,MATLAB图线先下平移

热门文章

  1. python tcp socket.connect() [Errno 56] Socket is already connectedconnect
  2. 实数系的基本定理_11、实数的连续性(1)
  3. python实数符号_下列格式化符号中,用来表示浮点实数的是()。 (6.0分)_学小易找答案...
  4. Python3 XML解析
  5. 小程序 自定义气泡框
  6. 浏览器打开pdf文件默认全屏设置方法
  7. ceph pg peering和恢复 (2)
  8. 为资产分类定义折旧范围_SAP FICO-AA资产知识要点.doc
  9. 什么是ECS框架?讲解 + 实战带你入门ECS框架
  10. Steam Deck 游戏掌机可运行 Windows