【Android】自定义View —— 滑动的次数选择器
来源:互联网 发布:mac删除开机密码 编辑:程序博客网 时间:2024/06/06 05:33
【关键词】
自定义View
次数选择器
滑动
【问题】
- 实现一个可滑动的次数选择器;
【效果图】
「原型图」
「实现图」
【分析】
- 对外提供简单的Change监听接口;
- 如果处于两者之间就需要做判断:大于一半就自动跳转到下一个,小于一半,则回到上一个;
- 通过
Scroller
及其startScroll()
方法来实现回弹效果; - 要灵活控制刻度的最小值和最大值,因为可能随着需求的更改,这个值很容易发生改变(即处理好对应关系);
- 在自定义View中只画刻度和文字,至于红色的指针和外面的透明渐变图层则可以直接在布局文件中实现:
一方面比起在java代码
中更容易实现,另一方面更灵活(如果想要去掉渐变图层,只需要修改布局文件,而不需要对java代码
进行任何修改);
【解决方案】
- 我最开始是通过不断的设置
padding
来实现,但是一时头脑不清晰,没有处理好对应关系,就重新改用scroll
来实现了;
【代码】
「客户端用法代码」
布局代码activity_count_view.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="100dp" android:background="#ffffff" android:orientation="vertical"> <!-- 刻度 --> <com.lyloou.android.view.CountView android:id="@+id/cv_main" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:layout_marginEnd="48dp" android:layout_marginStart="48dp" android:background="#ffffff" /> <!-- 中间的指针 --> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@mipmap/reminder_slider" /> <!-- 遮罩层 --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:orientation="horizontal"> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:background="#ffffff" /> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="4" android:background="@drawable/gradient_count_view" /> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:background="#ffffff" /> </LinearLayout></RelativeLayout>
Activity对布局文件的初始化
public class CountViewActivity extends AppCompatActivity { private Activity mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; setContentView(R.layout.activity_count_view); initView(); } private void initView() { CountView countView = (CountView) findViewById(R.id.cv_main); if (countView != null) { // int index = countView.getIndex(); // 获取当前值 // countView.setIndex(6);// 设置默认值 countView.setOnChangeListener(new CountView.OnChangeListener() { @Override public void doIndex(int index) { Utoast.show(mContext, "选中了:" + index + "次"); } }); } }}
中间的渐变shape gradient_count_view.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <gradient android:angle="180" android:centerColor="#10ffffff" android:endColor="#ffffff" android:startColor="#ffffff" /></shape>
「通用源代码」
自定义View
package com.lyloou.android.view;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.text.TextPaint;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.Scroller;import com.lyloou.android.util.Uscreen;public class CountView extends View { public interface OnChangeListener { void doIndex(int index); } private final Context CONTEXT = getContext(); private final int W = Uscreen.dp2Px(CONTEXT, 36);// 每一项的固定长度 private final int LINE_H = Uscreen.dp2Px(CONTEXT, 6); // 长直线的厚度 private final int ITEM_LINE_W = LINE_H / 3; // 竖直刻度直线的厚度 private final int ITEM_LINE_H = Uscreen.dp2Px(CONTEXT, 16); // 竖直刻度直线的高度 private final int BOTTOM_FONT_SIZE = (int) Uscreen.sp2Px(CONTEXT, 12); // 底部的文字大小 private static final int COLOR_LINE = Color.parseColor("#4422f9"); // 长直线和刻度线的颜色 private static final int MIN_ITEM = 1; // 显示的最小刻度值 private static final int MAX_ITEM = 20; // 显示的最大刻度值 private static final int EXTRA_COUNT = 2; // 左边和右边额外的刻度个数 private Paint mLinePaint; private TextPaint mTextPaint; private Scroller mScroller; private OnChangeListener mChangeListener; public CountView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setUp(); initData(); } public CountView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CountView(Context context) { this(context, null); } private void setUp() { mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mLinePaint.setColor(COLOR_LINE); mTextPaint = new TextPaint(); mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextSize(BOTTOM_FONT_SIZE); mScroller = new Scroller(CONTEXT); } private void initData() { setIndex(MIN_ITEM); } private int mLastX; @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: int x = (int) event.getX(); int deltaX = x - mLastX; scrollBy(-deltaX, 0); mLastX = x; break; case MotionEvent.ACTION_UP: doIndex(getIndex()); break; } return true; } private void doIndex(int index) { if (mChangeListener != null) { mChangeListener.doIndex(index + MIN_ITEM); } } public int getIndex() { int index = 0; int scrollX = getScrollX(); index = scrollX / W; if (scrollX <= 0) { index = 0; smoothScrollTo(index); } else if (index >= (MAX_ITEM - MIN_ITEM)) { index = MAX_ITEM - MIN_ITEM; smoothScrollTo(index * W); } else { int shift = scrollX % W; if (shift >= W / 2) { index++; smoothScrollBy(W - shift); } else { smoothScrollBy(-shift); } } return index; } public void setIndex(int index) { int newIndex = index - MIN_ITEM; scrollTo(newIndex * W, 0); } public void setOnChangeListener(OnChangeListener listener) { mChangeListener = listener; } private void smoothScrollTo(int dextX) { smoothScrollBy(dextX - getScrollX()); } private void smoothScrollBy(int deltaX) { mScroller.startScroll(getScrollX(), 0, deltaX, 0, 320); invalidate(); } @Override public void computeScroll() { if (mScroller != null && mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int shift = getWidth() / 2 - W / 2; // 将原点移到屏幕中间; int height = getHeight(); for (int i = MIN_ITEM - EXTRA_COUNT; i < MAX_ITEM + EXTRA_COUNT; i++) { int startX = (i - MIN_ITEM) * W + shift; // 画直线 mLinePaint.setStrokeWidth(LINE_H); canvas.drawLine(startX, height / 2, startX + W, height / 2, mLinePaint); // 画刻度 mLinePaint.setStrokeWidth(ITEM_LINE_W); canvas.drawLine(startX + W / 2, height / 2 - ITEM_LINE_H, startX + W / 2, height / 2, mLinePaint); // 在刻度范围内,才画文字 if (i >= MIN_ITEM && i <= MAX_ITEM) { String text = i + "次"; float textWidth = mTextPaint.measureText(text); float textHeight = mTextPaint.getFontMetrics().bottom; canvas.drawText(text, startX + (W - textWidth) / 2, (height + textHeight) / 2 + textHeight * 10, mTextPaint); } } }}
【参考资料】
- 回弹效果的代码参考了《Android开发艺术探索》P136
0 0
- 【Android】自定义View —— 滑动的次数选择器
- Android自定义view——滚动选择器
- Android自定义View实战(SlideTab-可滑动的选择器)
- 自定义View—弹性滑动
- android自定义View——等级滑动条
- Android自定义View——滑动变色指示器
- Android自定义View示例(三)—滑动控件
- Android自定义View示例(二)—滑动开关
- Android开发——View的滑动
- Android开发进阶—View的滑动
- Android 自定义View:实现View的滑动效果
- Android 自定义View:实现View的滑动效果
- android自定义view--色彩选择器
- Android自定义View 时段选择器
- Android 自定义滑动容器View
- Android:View滑动与自定义
- 自定义View——弹性滑动
- 仿IOS特效(一)——Android 自定义View实现3D滚轮效果的城市联动选择器
- android studio 学习笔记之 全面进阶配置技巧
- 记第一次电话面试(百度)
- Android的Handler,Looper消息机制问题
- 文章标题
- C++_DFS求连通度
- 【Android】自定义View —— 滑动的次数选择器
- Xcode关于拖拽窗口导致获取文件全路径错误的问题
- 大搬家
- 九度OJ - 1350 - 二叉树的深度
- java网络编程--udp传输示例
- APS.NET_MVC5学习笔记-验证编辑方法(Edit method)和编辑视图(Edit view)
- Android中的通知 Notification
- 第一章 JAVA入门(数据输入之EchoText类)
- Android View系列一: View基础知识