Android自定义标尺滑动选择值效果

发布时间:2020-10-16 07:40:15

来源:脚本之家

阅读:130

作者:676598624

本文实例为大家分享了Android实现滑动标尺选择值,效果图

1.自定义属性attrs.xml

2.自定义RulerView

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.VelocityTracker;

import android.view.View;

import android.view.ViewConfiguration;

import android.widget.Scroller;

public class RulerView extends View {

private int mMinVelocity;

private Scroller mScroller; //Scroller是一个专门用于处理滚动效果的工具类 用mScroller记录/计算View滚动的位置,再重写View的computeScroll(),完成实际的滚动

private VelocityTracker mVelocityTracker; //主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率。

private int mWidth;

private int mHeight;

private float mSelectorValue = 50.0f; // 未选择时 默认的值 滑动后表示当前中间指针正在指着的值

private float mMaxValue = 200; // 最大数值

private float mMinValue = 100.0f; //最小的数值

private float mPerValue = 1; //最小单位 如 1:表示 每2条刻度差为1. 0.1:表示 每2条刻度差为0.1

// 在demo中 身高mPerValue为1 体重mPerValue 为0.1

private float mLineSpaceWidth = 5; // 尺子刻度2条线之间的距离

private float mLineWidth = 4; // 尺子刻度的宽度

private float mLineMaxHeight = 420; // 尺子刻度分为3中不同的高度。 mLineMaxHeight表示最长的那根(也就是 10的倍数时的高度)

private float mLineMidHeight = 30; // mLineMidHeight 表示中间的高度(也就是 5 15 25 等时的高度)

private float mLineMinHeight = 17; // mLineMinHeight 表示最短的那个高度(也就是 1 2 3 4 等时的高度)

private float mTextMarginTop = 10; //o

private float mTextSize = 30; //尺子刻度下方数字 textsize

private boolean mAlphaEnable = false; // 尺子 最左边 最后边是否需要透明 (透明效果更好点)

private float mTextHeight; //尺子刻度下方数字 的高度

private Paint mTextPaint; // 尺子刻度下方数字( 也就是每隔10个出现的数值) paint

private Paint mLinePaint; // 尺子刻度 paint

private int mTotalLine; //共有多少条 刻度

private int mMaxOffset; //所有刻度 共有多长

private float mOffset; // 默认状态下,mSelectorValue所在的位置 位于尺子总刻度的位置

private int mLastX, mMove;

private OnValueChangeListener mListener; // 滑动后数值回调

private int mLineColor = Color.GRAY; //刻度的颜色

private int mTextColor = Color.BLACK; //文字的颜色

public RulerView(Context context) {

this(context, null);

}

public RulerView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public RulerView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init(context, attrs);

}

protected void init(Context context, AttributeSet attrs) {

mScroller = new Scroller(context);

this.mLineSpaceWidth = myfloat(25.0F);

this.mLineWidth = myfloat(2.0F);

this.mLineMaxHeight = myfloat(100.0F);

this.mLineMidHeight = myfloat(60.0F);

this.mLineMinHeight = myfloat(40.0F);

this.mTextHeight = myfloat(40.0F);

final TypedArray typedArray = context.obtainStyledAttributes(attrs,

R.styleable.RulerView);

mAlphaEnable = typedArray.getBoolean(R.styleable.RulerView_alphaEnable, mAlphaEnable);

mLineSpaceWidth = typedArray.getDimension(R.styleable.RulerView_lineSpaceWidth, mLineSpaceWidth);

mLineWidth = typedArray.getDimension(R.styleable.RulerView_lineWidth, mLineWidth);

mLineMaxHeight = typedArray.getDimension(R.styleable.RulerView_lineMaxHeight, mLineMaxHeight);

mLineMidHeight = typedArray.getDimension(R.styleable.RulerView_lineMidHeight, mLineMidHeight);

mLineMinHeight = typedArray.getDimension(R.styleable.RulerView_lineMinHeight, mLineMinHeight);

mLineColor = typedArray.getColor(R.styleable.RulerView_lineColor, mLineColor);

mTextSize = typedArray.getDimension(R.styleable.RulerView_textSize, mTextSize);

mTextColor = typedArray.getColor(R.styleable.RulerView_textColor, mTextColor);

mTextMarginTop = typedArray.getDimension(R.styleable.RulerView_textMarginTop, mTextMarginTop);

mSelectorValue = typedArray.getFloat(R.styleable.RulerView_selectorValue, 0.0f);

mMinValue = typedArray.getFloat(R.styleable.RulerView_minValue, 0.0f);

mMaxValue = typedArray.getFloat(R.styleable.RulerView_maxValue, 100.0f);

mPerValue = typedArray.getFloat(R.styleable.RulerView_perValue, 0.1f);

mMinVelocity = ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();

mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mTextPaint.setTextSize(mTextSize);

mTextPaint.setColor(mTextColor);

mTextHeight = getFontHeight(mTextPaint);

mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mLinePaint.setStrokeWidth(mLineWidth);

mLinePaint.setColor(mLineColor);

// setValue(1990, 1940, 2016, 1);

}

public static int myfloat(float paramFloat) {

return (int) (0.5F + paramFloat * 1.0f);

}

private float getFontHeight(Paint paint) {

Paint.FontMetrics fm = paint.getFontMetrics();

return fm.descent - fm.ascent;

}

/**

* @param selectorValue 未选择时 默认的值 滑动后表示当前中间指针正在指着的值

* @param minValue 最大数值

* @param maxValue 最小的数值

* @param per 最小单位 如 1:表示 每2条刻度差为1. 0.1:表示 每2条刻度差为0.1 在demo中 身高mPerValue为1 体重mPerValue 为0.1

*/

public void setValue(float selectorValue, float minValue, float maxValue, float per) {

this.mSelectorValue = selectorValue;

this.mMaxValue = maxValue;

this.mMinValue = minValue;

this.mPerValue = (int) (per * 10.0f);

this.mTotalLine = ((int) ((mMaxValue * 10 - mMinValue * 10) / mPerValue)) + 1;

mMaxOffset = (int) (-(mTotalLine - 1) * mLineSpaceWidth);

mOffset = (mMinValue - mSelectorValue) / mPerValue * mLineSpaceWidth * 10;

invalidate();

setVisibility(VISIBLE);

}

public void setOnValueChangeListener(OnValueChangeListener listener) {

mListener = listener;

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

if (w > 0 && h > 0) {

mWidth = w;

mHeight = h;

}

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

float left, height;

String value;

int alpha = 0;

float scale;

int srcPointX = mWidth / 2;

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

left = srcPointX + mOffset + i * mLineSpaceWidth;

if (left < 0 || left > mWidth) {

continue; // 先画默认值在正中间,左右各一半的view。 多余部分暂时不画(也就是从默认值在中间,画旁边左右的刻度线)

}

/*文字*/

if (i % 10 == 0) {

value = String.valueOf((int) (mMinValue + i * mPerValue / 10));

if (mAlphaEnable) {

mTextPaint.setAlpha(alpha);

}

canvas.drawText(value, left - mTextPaint.measureText(value) / 2,

mTextHeight, mTextPaint); // 在为整数时,画 数值

}

/*线条*/

if (i % 10 == 0) {

height = mLineMinHeight;

} else if (i % 5 == 0) {

height = mLineMidHeight;

} else {

height = mLineMaxHeight;

}

if (mAlphaEnable) {

scale = 1 - Math.abs(left - srcPointX) / srcPointX;

alpha = (int) (255 * scale * scale);

mLinePaint.setAlpha(alpha);

}

canvas.drawLine(left, mLineMaxHeight + mTextMarginTop + mTextHeight, left, height, mLinePaint);

}

}

@Override

public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction();

int xPosition = (int) event.getX();

if (mVelocityTracker == null) {

mVelocityTracker = VelocityTracker.obtain();

}

mVelocityTracker.addMovement(event);

switch (action) {

case MotionEvent.ACTION_DOWN:

mScroller.forceFinished(true);

mLastX = xPosition;

mMove = 0;

break;

case MotionEvent.ACTION_MOVE:

mMove = (mLastX - xPosition);

changeMoveAndValue();

break;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_CANCEL:

countMoveEnd();

countVelocityTracker();

return false;

default:

break;

}

mLastX = xPosition;

return true;

}

private void countVelocityTracker() {

mVelocityTracker.computeCurrentVelocity(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);

}

}

/**

* 滑动结束后,若是指针在2条刻度之间时,改变mOffset 让指针正好在刻度上。

*/

private void countMoveEnd() {

mOffset -= mMove;

if (mOffset <= mMaxOffset) {

mOffset = mMaxOffset;

} else if (mOffset >= 0) {

mOffset = 0;

}

mLastX = 0;

mMove = 0;

mSelectorValue = mMinValue + Math.round(Math.abs(mOffset) * 1.0f / mLineSpaceWidth) * mPerValue / 10.0f;

mOffset = (mMinValue - mSelectorValue) * 10.0f / mPerValue * mLineSpaceWidth;

notifyValueChange();

postInvalidate();

}

/**

* 滑动后的操作

*/

private void changeMoveAndValue() {

mOffset -= mMove;

if (mOffset <= mMaxOffset) {

mOffset = mMaxOffset;

mMove = 0;

mScroller.forceFinished(true);

} else if (mOffset >= 0) {

mOffset = 0;

mMove = 0;

mScroller.forceFinished(true);

}

mSelectorValue = mMinValue + Math.round(Math.abs(mOffset) * 1.0f / mLineSpaceWidth) * mPerValue / 10.0f;

notifyValueChange();

postInvalidate();

}

private void notifyValueChange() {

if (null != mListener) {

mListener.onValueChange(mSelectorValue);

}

}

/**

* 滑动后的回调

*/

public interface OnValueChangeListener {

void onValueChange(float value);

}

@Override

public void computeScroll() {

super.computeScroll();

if (mScroller.computeScrollOffset()) { //mScroller.computeScrollOffset()返回 true表示滑动还没有结束

if (mScroller.getCurrX() == mScroller.getFinalX()) {

countMoveEnd();

} else {

int xPosition = mScroller.getCurrX();

mMove = (mLastX - xPosition);

changeMoveAndValue();

mLastX = xPosition;

}

}

}

}

3.xml中使用activity_main.xml

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:gravity="center_horizontal"

android:orientation="vertical"

android:visibility="visible">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:includeFontPadding="false"

android:maxHeight="17.0sp"

android:text="身高(cm)"

android:textColor="#cc222222"

android:textSize="15.0sp" />

android:id="@+id/tv_info_height_value"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="11.0dip"

android:includeFontPadding="false"

android:maxHeight="24.0sp"

android:textColor="#cc222222"

android:textSize="24.0sp" />

android:layout_width="fill_parent"

android:layout_height="wrap_content">

android:id="@+id/ruler_height"

android:layout_width="fill_parent"

android:layout_height="68.0dip"

android:layout_marginTop="24.0dip"

app:alphaEnable="true"

app:lineColor="@color/gray"

app:lineMaxHeight="40dp"

app:lineMidHeight="30dp"

app:lineMinHeight="20dp"

app:lineSpaceWidth="10dp"

app:lineWidth="2dip"

app:maxValue="250.0"

app:minValue="80.0"

app:perValue="1"

app:textColor="@color/black" />

android:layout_width="14.0dip"

android:layout_height="46.0dip"

android:layout_centerHorizontal="true"

android:layout_marginTop="40.0dip"

android:scaleType="fitXY"

android:src="@drawable/info_ruler" />

android:id="@+id/click"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="10dp"

android:text="点击改变" />

4.Activity中使用MainActivity

public class MainActivity extends AppCompatActivity {

private int maxValue = 250;

private int minValue = 80;

private RulerView rulerHeight;

private TextView tvHeightValue;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

rulerHeight = (RulerView) findViewById(R.id.ruler_height);

tvHeightValue = (TextView) findViewById(R.id.tv_info_height_value);

showNumInt();

findViewById(R.id.click).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

showNumInt();

}

});

rulerHeight.setOnValueChangeListener(new RulerView.OnValueChangeListener() {

@Override

public void onValueChange(float value) {

tvHeightValue.setText(String.valueOf(value));

}

});

}

private void showNumInt() {

Random rand = new Random();

int value = rand.nextInt(maxValue - minValue + 1) + minValue;

rulerHeight.setValue(value, minValue, maxValue, 1);

tvHeightValue.setText(String.valueOf(Integer.valueOf(value)));

}

}

PS:可自行根据需要绘制线条和文字,上下选择文字位置。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。

android自定义标尺,Android自定义标尺滑动选择值效果相关推荐

  1. android 仿搜索动画,Android仿京东顶部搜索框滑动伸缩动画效果

    最近使用京东发现,京东顶部的搜索框有一个新的伸缩效果,根据用户的手势滑动,伸缩搜索框.觉得效果还不错,就看了下其他的应用有没有这种伸缩的效果,发现安居客也使用了类似的一种效果,然后就想着实现这样的一种 ...

  2. ionic3滑动选择刻度尺效果

    因为业务需要一个像刻度一样的效果用手或者鼠标按住刻度尺的部分左右滑动可以改变上面的数值的效果 首先创建ionic3项目:ionic start keduchi tabs 目录如下: 需要用到的图片: ...

  3. 实现类似淘票票电影滑动选择的效果

    https://github.com/yarolegovich/DiscreteScrollView 无意中找到github里的好资源,自己做个笔记,之前找类似的很久,回头细写下.

  4. Android移动应用开发之Viewpage2+fragment实现微信滑动界面的效果

    文章目录 布局 viewpager2 fragment adapter 实现的效果如下: 滑动界面能够实现界面的跳转. 点击下面按钮同样实现界面的跳转. 布局 最下面的导航栏,单独写了个布局文件: & ...

  5. android 自定义裁剪 陌陌,Android之View篇6————仿陌陌卡片左右滑动选择布局

    Android之View篇6----仿陌陌卡片左右滑动选择控件 一.目录 Android之View篇6----仿陌陌卡片左右滑动选择控件 一.目录 二.效果图 三.业务需求梳理 四.思路分析 1. 新 ...

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

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

  7. Kotlin 自定义View之实现标尺控件(选择身高、体重等)

    本篇文章讲的是Kotlin 自定义view之实现标尺控件Ruler,以选择身高.体重等.开发中,当我们需要获取用户的身高和体重等信息时,如果直接让他们输入,显然体验不够好.像类似于唯品会.好轻等APP ...

  8. android 自定义event,Android运用onTouchEvent自定义滑动布局

    写在自定义之前 我们也许会遇到,自定义控件的触屏事件处理,先来了解一下View类中的,onTouch事件和onTouchEvent事件. 1.boolean onTouch(View v, Motio ...

  9. 【Android 内存优化】自定义组件长图组件 ( 长图滚动区域解码 | 手势识别 GestureDetector | 滑动计算类 Scroller | 代码示例 )

    文章目录 一.GestureDetector 创建与设置 二.GestureDetector 触摸事件传递 三.触摸滑动操作 四.惯性滑动操作 五.长图滑动组件代码示例 六.运行效果 七.源码及资源下 ...

最新文章

  1. 【转】造成segment fault,产生core dump的可能原因
  2. 台湾国立大学郭彦甫Matlab教程笔记(14)polynomial differentiation多项式微分
  3. echarts mysql_ECharts实现mysql 数据图表化
  4. bzoj1612 Usaco08 Jan 牛大赛
  5. mysql5.7安装完成后密码是多少_安装了mysql5.7后,如何进行配置(密码等)初始化...
  6. vector的学习(系统的学习)
  7. 在WebStorm里配置watcher实现编辑less文件时自动生成.css文件
  8. 导出zabbix的IT service报表
  9. layui 滚动加载与ajax,909422229_layUi关于ajax与loading问题
  10. [OT]“蓝帽”会议
  11. 【简单的四足机器人制作(基于STC15/LPC845)】
  12. 如何管理网络营销渠道冲突?
  13. win10,在proe/creo中鼠标中键不能放大缩小
  14. 狂神ajax,Ajax---狂神说
  15. e^(At)求解方法及其含义–线性微分方程的求解
  16. w ndows10输入法设置,Win10输入法设置技巧:切换输入法
  17. 服务器做虚拟网吧,一种基于游戏的虚拟网吧实现方法
  18. java 兔子繁殖问题_兔子繁殖问题
  19. dat2img格式转换-ROM定制开发教程
  20. 深度学习平台——Paddle核心框架介绍

热门文章

  1. Js 的防抖与节流代码分析
  2. Tiled的qbs方式编译记录
  3. 微信小程序---365笔记第48天---上一题,下一题
  4. 对拉格朗日乘数法的直观认识
  5. 【LVGL应用开发--基于STM32】第1章 初识LVGL
  6. 谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo
  7. Xmanager 5问题记录
  8. 【VMware Fusion】如何配置VMware Fusion中的Vmnet网卡
  9. suse linux 11 xdm图形化,suse xdm 设置
  10. 判断电脑是否安装WPS