Android自定义控件实现按钮滚动选择效果

本文实例为大家分享了Android实现按钮滚动选择效果的具体代码,供大家参考,具体内容如下

效果图

代码实现

package com.demo.ui.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.demo.R;
import com.demo.factory.Axis;
import com.demo.utils.LogUtils;

import java.util.ArrayList;
import java.util.List;

public class AirTemperatureView extends RelativeLayout{

 private Context context;
 private TextView tv;
 private TextView tv_middle;
 // private TextView tv_middle_small;
 private RelativeLayout Auto_layout;
 private StringScrollPicker stringScrollPicker;
 private List<CharSequence> newList;
 private ImageView img;
 private ImageView img_left;
 private ImageView img_right;

 private int mPosition;
 private Handler handler = new Handler();
 /**
 * 延迟线程,看是否还有下一个字符输入
 */
 private Runnable delayRun = new Runnable() {
 @Override
 public void run() {
  stringScrollPicker.setVisibility(INVISIBLE);
  img.setBackgroundResource(R.drawable.air_temp_bg);
  tv_middle.setText(newList.get(mPosition));
  //tv.setText("电池剩余"+newList.get(mPosition)+"%提醒你");
  tv_middle.setVisibility(VISIBLE);
  img_right.setVisibility(VISIBLE);
  img_left.setVisibility(VISIBLE);

  if(mListener != null) {
  mListener.setAirTemper(mPosition+18);
  }
  LogUtils.e("空调刷新===","温度");

 }
 };

 public AirTemperatureView(Context context){
 super(context);
 this.context = context;
 init();
 }

 @TargetApi(Build.VERSION_CODES.M)
 public void init(){
 super.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, Axis.scaleX(230)));
 LinearLayout parent = new LinearLayout(context);
 parent.setOrientation(LinearLayout.VERTICAL);
 LayoutParams parent_Params = new LayoutParams(LayoutParams.MATCH_PARENT, Axis.scaleX(230));
 super.addView(parent,parent_Params);

 RelativeLayout tv_layout = new RelativeLayout(context);
 LinearLayout.LayoutParams tv_layout_Params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, Axis.scaleX(50));
 parent.addView(tv_layout,tv_layout_Params);
 tv = new TextView(context);
 tv.setText("温度");
 tv.setTextSize(Axis.scaleTextSize(36));
 tv.setTextColor(ContextCompat.getColor(context, R.color.white_70_color));//
 LayoutParams tv_Params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
 tv_Params.addRule(RelativeLayout.CENTER_IN_PARENT);
 tv_layout.addView(tv,tv_Params);

 /**
  * 滑动选择器
  */
 Auto_layout = new RelativeLayout(context);
 LinearLayout.LayoutParams Auto_layout_Params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, Axis.scaleX(150));
 Auto_layout_Params.setMargins(0,Axis.scaleX(30),0,0);
 parent.addView(Auto_layout,Auto_layout_Params);

 img = new ImageView(context);
 img.setId(R.id.EleRemindImage);
 img.setBackgroundResource(R.drawable.air_temp_bg);
 LayoutParams img_Params = new LayoutParams(Axis.scaleX(150), Axis.scaleX(150));
 img_Params.addRule(RelativeLayout.CENTER_IN_PARENT);
 Auto_layout.addView(img,img_Params);

 img_left = new ImageView(context);
 img_left.setBackgroundResource(R.drawable.battery_point);
 LayoutParams img_left_Params = new LayoutParams(Axis.scaleX(14), Axis.scaleX(14));
 img_left_Params.addRule(RelativeLayout.CENTER_VERTICAL);
 img_left_Params.addRule(RelativeLayout.LEFT_OF,R.id.EleRemindImage);
 img_left_Params.setMargins(0,0,Axis.scaleX(134),0);
 Auto_layout.addView(img_left,img_left_Params);

 img_right = new ImageView(context);
 img_right.setBackgroundResource(R.drawable.battery_point);
 LayoutParams img_right_Params = new LayoutParams(Axis.scaleX(14), Axis.scaleX(14));
 img_right_Params.addRule(RelativeLayout.CENTER_VERTICAL);
 img_right_Params.addRule(RelativeLayout.RIGHT_OF,R.id.EleRemindImage);
 img_right_Params.setMargins(Axis.scaleX(134),0,0,0);
 Auto_layout.addView(img_right,img_right_Params);

 tv_middle = new TextView(context);
 tv_middle.setTextSize(Axis.scaleTextSize(64));
 tv_middle.setGravity(Gravity.CENTER);
 tv_middle.setTextColor(0xFFFFFFFF);
 LayoutParams tv_middle_Params = new LayoutParams(Axis.scaleX(150), Axis.scaleX(150));
 tv_middle_Params.addRule(RelativeLayout.CENTER_IN_PARENT);
 Auto_layout.addView(tv_middle,tv_middle_Params);

 newList = new ArrayList<>();
 newList.add("18");
 newList.add("19");
 newList.add("20");
 newList.add("21");
 newList.add("22");
 newList.add("23");
 newList.add("24");
 newList.add("25");
 newList.add("26");
 newList.add("27");
 newList.add("28");
 newList.add("29");
 newList.add("30");
 newList.add("31");
 newList.add("32");

 tv_middle.setText(newList.get(0));

 stringScrollPicker = new StringScrollPicker(context);
 stringScrollPicker.setHorizontal(true);
 stringScrollPicker.setVisibleItemCount(5);//可见5个 第3个 (3-1)个位中间
 stringScrollPicker.setCenterPosition(2);
 stringScrollPicker.setIsCirculation(true);
 stringScrollPicker.setCanTap(true);
 stringScrollPicker.setDisallowInterceptTouch(true);
 LayoutParams stringScrollPicker_Params = new LayoutParams(LayoutParams.MATCH_PARENT,Axis.scaleX(150));
 Auto_layout.addView(stringScrollPicker,stringScrollPicker_Params);
 stringScrollPicker.setData(newList);
 stringScrollPicker.setOnSelectedListener(new ScrollPickerView.OnSelectedListener() {
  @Override
  public void onSelected(ScrollPickerView scrollPickerView, final int position) {
  mPosition = position;
  handler.postDelayed(delayRun, 1500);

  }
 });

 stringScrollPicker.setOnSelectedListener(new StringScrollPicker.OnDataSelectedListener() {
  @Override
  public void DataSelected(CharSequence data) {
  //tv.setText("电池剩余"+data+"%提醒你");
  }
 });

 stringScrollPicker.setSelectedPosition(0,false);//中间Item位置

 stringScrollPicker.setVisibility(INVISIBLE);

 stringScrollPicker.setOnTouchListener(new OnTouchListener() {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
  switch (event.getAction()){
   case MotionEvent.ACTION_DOWN:
   img.setBackgroundResource(R.drawable.battery_btn_p);
   if(delayRun!=null){
    handler.removeCallbacks(delayRun);
   }
   break;
  }
  return false;
  }
 });

 img.setOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
  stringScrollPicker.setVisibility(VISIBLE);
  tv_middle.setVisibility(INVISIBLE);
  img_right.setVisibility(INVISIBLE);
  img_left.setVisibility(INVISIBLE);
  img.setBackgroundResource(R.drawable.battery_btn_p);

  }
 });
 }
 /**
 * 风速设置
 * @param mPosition
 */
 public void setAirTemperature(int mPosition){
 /**
  * 在设置的时候不刷新
  */
 if(stringScrollPicker.getVisibility() == INVISIBLE){
  if(mPosition > 32){
  mPosition = 32;
  }
  stringScrollPicker.setSelectedPosition(mPosition-18,false);
  tv_middle.setText(newList.get(mPosition-18));
 }
 }

 public TemperatureListener mListener;
 public void setOnTemperatureListener (TemperatureListener listener) {
 mListener = listener;
 }
 public interface TemperatureListener {
 void setAirTemper(int temperature);
 }

}

StringScrollPicker 类

package com.demo.ui.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;

import com.demo.factory.Axis;
import com.demo.utils.ColorUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class StringScrollPicker extends ScrollPickerView<CharSequence> {

 private int mMeasureWidth;
 private int mMeasureHeight;

 private TextPaint mPaint; //
 private int mMinTextSize = Axis.scaleX(64); // 最小的字体
 private int mMaxTextSize = Axis.scaleX(64); // 最大的字体
 // 字体渐变颜色
 private int mStartColor = Color.WHITE; // 中间选中item的颜色
 private int mEndColor = Color.GRAY; // 上下两边的颜色

 private int mMaxLineWidth = -1; // 最大的行宽,默认为itemWidth.超过后文字自动换行
 private Layout.Alignment mAlignment = Layout.Alignment.ALIGN_CENTER; // 对齐方式,默认居中

 @TargetApi(Build.VERSION_CODES.CUPCAKE)
 public StringScrollPicker(Context context) {
 this(context, null);
 }

 @RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
 public StringScrollPicker(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 }

 @RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
 public StringScrollPicker(Context context, AttributeSet attrs,
    int defStyleAttr) {
 super(context, attrs, defStyleAttr);

 mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
 mPaint.setStyle(Paint.Style.FILL);
 mPaint.setColor(Color.BLACK);

 setData(new ArrayList<CharSequence>(Arrays.asList(new String[]{
  "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"
 })));

 }

 /**
 * @param startColor 正中间的颜色
 * @param endColor 上下两边的颜色
 */
 public void setColor(int startColor, int endColor) {
 mStartColor = startColor;
 mEndColor = endColor;
 invalidate();
 }

 /**
 * item文字大小
 *
 * @param minText 沒有被选中时的最小文字
 * @param maxText 被选中时的最大文字
 */
 public void setTextSize(int minText, int maxText) {
 mMinTextSize = minText;
 mMaxTextSize = maxText;
 invalidate();
 }

 public int getStartColor() {
 return mStartColor;
 }

 public int getEndColor() {
 return mEndColor;
 }

 public int getMinTextSize() {
 return mMinTextSize;
 }

 public int getMaxTextSize() {
 return mMaxTextSize;
 }

 public int getMaxLineWidth() {
 return mMaxLineWidth;
 }

 /**
 * 最大的行宽,默认为itemWidth.超过后文字自动换行
 * @param maxLineWidth
 */
 public void setMaxLineWidth(int maxLineWidth) {
 mMaxLineWidth = maxLineWidth;
 }

 /**
 * 最大的行宽,默认为itemWidth.超过后文字自动换行
 * @return
 */
 public Layout.Alignment getAlignment() {
 return mAlignment;
 }

 public void setAlignment(Layout.Alignment alignment) {
 mAlignment = alignment;
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 super.onSizeChanged(w, h, oldw, oldh);
 mMeasureWidth = getMeasuredWidth();
 mMeasureHeight = getMeasuredHeight();
 if (mMaxLineWidth < 0) {
  mMaxLineWidth = getItemWidth();
 }
 }

 @Override
 public void drawItem(Canvas canvas, List<CharSequence> data, int position, int relative, float moveLength, float top) {
 CharSequence text = data.get(position);
 int itemSize = getItemSize();

 // 设置文字大小
 if (relative == -1) { // 上一个
  if (moveLength < 0) { // 向上滑动
  mPaint.setTextSize(mMinTextSize);
  } else { // 向下滑动
  mPaint.setTextSize(mMinTextSize + (mMaxTextSize - mMinTextSize)
   * moveLength / itemSize);
  }
 } else if (relative == 0) { // 中间item,当前选中
  mPaint.setTextSize(mMinTextSize + (mMaxTextSize - mMinTextSize)
   * (itemSize - Math.abs(moveLength)) / itemSize);
 } else if (relative == 1) { // 下一个
  if (moveLength > 0) { // 向下滑动
  mPaint.setTextSize(mMinTextSize);
  } else { // 向上滑动
  mPaint.setTextSize(mMinTextSize + (mMaxTextSize - mMinTextSize)
   * -moveLength / itemSize);
  }
 } else { // 其他
  mPaint.setTextSize(mMinTextSize);
 }

 StaticLayout layout = new StaticLayout(text, 0, text.length(), mPaint, mMaxLineWidth, mAlignment, 1.0F, 0.0F, true, null, 0);
 float x = 0;
 float y = 0;
 float lineWidth = layout.getWidth();

 if (isHorizontal()) { // 水平滚动
  x = top + (getItemWidth() - lineWidth) / 2;
  y = (getItemHeight() - layout.getHeight()) / 2;
 } else { // 垂直滚动
  x = (getItemWidth() - lineWidth) / 2;
  y = top + (getItemHeight() - layout.getHeight()) / 2;
 }
 // 计算渐变颜色
 computeColor(relative, itemSize, moveLength,text);
// canvas.drawText(text, x, y, mPaint);

 canvas.save();
 canvas.translate(x, y);
 layout.draw(canvas);
 canvas.restore();
 }

 /**
 * 计算字体颜色,渐变
 *
 * @param relative  相对中间item的位置
 */
 private String lastString;
 private String nowSring;
 private void computeColor(int relative, int itemSize, float moveLength, CharSequence text) {

 int color = mEndColor; //  其他默认为mEndColor

 if (relative == -1 || relative == 1) { // 上一个或下一个
  // 处理上一个item且向上滑动 或者 处理下一个item且向下滑动 ,颜色为mEndColor
  if ((relative == -1 && moveLength < 0)
   || (relative == 1 && moveLength > 0)) {
  color = mEndColor;
  } else { // 计算渐变的颜色
  float rate = (itemSize - Math.abs(moveLength))
   / itemSize;
  color = ColorUtil.computeGradientColor(mStartColor, mEndColor, rate);
  }
 } else if (relative == 0) { // 中间item
  float rate = Math.abs(moveLength) / itemSize;
  color = ColorUtil.computeGradientColor(mStartColor, mEndColor, rate);

  nowSring = text.toString();
  if(nowSring != lastString){
  Log.e("text=====",text+"");
  if(mListener != null){
   mListener.DataSelected(text);
  }
  }
  lastString = nowSring;

 }

 mPaint.setColor(color);
 }

 public interface OnDataSelectedListener {
 void DataSelected(CharSequence data);
 }

 public void setOnSelectedListener(OnDataSelectedListener listener) {
 mListener = listener;
 }

 public OnDataSelectedListener mListener;

}

ScrollPickerView 类

package com.demo.ui.view;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.view.animation.Interpolator;
import android.widget.Scroller;

import com.demo.R;
import com.demo.utils.LogUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 滚动选择器,带惯性滑动
 */
public abstract class ScrollPickerView<T> extends View {

 private int mVisibleItemCount = 3; // 可见的item数量

 private boolean mIsInertiaScroll = true; // 快速滑动时是否惯性滚动一段距离,默认开启
 private boolean mIsCirculation = true; // 是否循环滚动,默认开启

 /*
 不允许父组件拦截触摸事件,设置为true为不允许拦截,此时该设置才生效
 当嵌入到ScrollView等滚动组件中,为了使该自定义滚动选择器可以正常工作,请设置为true
 */
 private boolean mDisallowInterceptTouch = false;

 private int mSelected; // 当前选中的item下标
 private int mLastSelected; // 当前选中的item下标

 private List<T> mData;
 private int mItemHeight = 0; // 每个条目的高度,当垂直滚动时,高度=mMeasureHeight/mVisibleItemCount
 private int mItemWidth = 0; // 每个条目的宽度,当水平滚动时,宽度=mMeasureWidth/mVisibleItemCount
 private int mItemSize; // 当垂直滚动时,mItemSize = mItemHeight;水平滚动时,mItemSize = mItemWidth
 private int mCenterPosition = -1; // 中间item的位置,0<=mCenterPosition<mVisibleItemCount,默认为 mVisibleItemCount / 2
 private int mCenterY; // 中间item的起始坐标y(不考虑偏移),当垂直滚动时,y= mCenterPosition*mItemHeight
 private int mCenterX; // 中间item的起始坐标x(不考虑偏移),当垂直滚动时,x = mCenterPosition*mItemWidth
 private int mCenterPoint; // 当垂直滚动时,mCenterPoint = mCenterY;水平滚动时,mCenterPoint = mCenterX
 private float mLastMoveY; // 触摸的坐标y
 private float mLastMoveX; // 触摸的坐标X

 private float mMoveLength = 0; // item移动长度,负数表示向上移动,正数表示向下移动

 private GestureDetector mGestureDetector;
 private OnSelectedListener mListener;

 private Scroller mScroller;
 private boolean mIsFling; // 是否正在惯性滑动
 private boolean mIsMovingCenter; // 是否正在滑向中间
 // 可以把scroller看做模拟的触屏滑动操作,mLastScrollY为上次触屏滑动的坐标
 private int mLastScrollY = 0; // Scroller的坐标y
 private int mLastScrollX = 0; // Scroller的坐标x

 private boolean mDisallowTouch = false; // 不允许触摸

 private Paint mPaint; //
 private Drawable mCenterItemBackground = null; // 中间选中item的背景色

 private boolean mCanTap = true; // 单击切换选项或触发点击监听器

 private boolean mIsHorizontal = false; // 是否水平滚动

 private boolean mDrawAllItem = false; // 是否绘制每个item(包括在边界外的item)

 @RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
 public ScrollPickerView(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 }

 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
 @RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
 public ScrollPickerView(Context context, AttributeSet attrs,
    int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 mGestureDetector = new GestureDetector(getContext(),
  new FlingOnGestureListener());
 mScroller = new Scroller(getContext());
 mAutoScrollAnimator = ValueAnimator.ofInt(0, 0);

 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mPaint.setStyle(Paint.Style.FILL);

 init(attrs);

 }

 private void init(AttributeSet attrs) {
 if (attrs != null) {
  TypedArray typedArray = getContext().obtainStyledAttributes(attrs,
   R.styleable.ScrollPickerView);

  if (typedArray.hasValue(R.styleable.ScrollPickerView_spv_center_item_background)) {
  setCenterItemBackground(typedArray.getDrawable(R.styleable.ScrollPickerView_spv_center_item_background));
  }
  setVisibleItemCount(typedArray.getInt(
   R.styleable.ScrollPickerView_spv_visible_item_count,
   getVisibleItemCount()));
  setCenterPosition(typedArray.getInt(
   R.styleable.ScrollPickerView_spv_center_item_position,
   getCenterPosition()));
  setIsCirculation(typedArray.getBoolean(R.styleable.ScrollPickerView_spv_is_circulation, isIsCirculation()));
  setDisallowInterceptTouch(typedArray.getBoolean(R.styleable.ScrollPickerView_spv_disallow_intercept_touch, isDisallowInterceptTouch()));
  setHorizontal(typedArray.getInt(R.styleable.ScrollPickerView_spv_orientation, mIsHorizontal ? 1 : 2) == 1);
  typedArray.recycle();
 }
 }

 @Override
 protected void onDraw(Canvas canvas) {

 if (mData == null || mData.size() <= 0) {
  return;
 }

 // 选中item的背景色
 if (mCenterItemBackground != null) {
  mCenterItemBackground.draw(canvas);
 }

 // 只绘制可见的item
 int length = Math.max(mCenterPosition + 1, mVisibleItemCount - mCenterPosition);
 int position;
 int start = Math.min(length, mData.size());
 if (mDrawAllItem) {
  start = mData.size();
 }
 // 上下两边
 for (int i = start; i >= 1; i--) { // 先从远离中间位置的item绘制,当item内容偏大时,较近的item覆盖在较远的上面

  if (mDrawAllItem || i <= mCenterPosition + 1) { // 上面的items,相对位置为 -i
  position = mSelected - i < 0 ? mData.size() + mSelected - i
   : mSelected - i;
  // 传入位置信息,绘制item
  if (mIsCirculation) {
   drawItem(canvas, mData, position, -i, mMoveLength, mCenterPoint + mMoveLength - i * mItemSize);
  } else if (mSelected - i >= 0) { // 非循环滚动
   drawItem(canvas, mData, position, -i, mMoveLength, mCenterPoint + mMoveLength - i * mItemSize);
  }
  }
  if (mDrawAllItem || i <= mVisibleItemCount - mCenterPosition) { // 下面的items,相对位置为 i
  position = mSelected + i >= mData.size() ? mSelected + i
   - mData.size() : mSelected + i;
  // 传入位置信息,绘制item
  if (mIsCirculation) {
   drawItem(canvas, mData, position, i, mMoveLength, mCenterPoint + mMoveLength + i * mItemSize);
  } else if (mSelected + i < mData.size()) { // 非循环滚动
   drawItem(canvas, mData, position, i, mMoveLength, mCenterPoint + mMoveLength + i * mItemSize);
  }
  }
 }
 // 选中的item
 drawItem(canvas, mData, mSelected, 0, mMoveLength, mCenterPoint + mMoveLength);
 }

 /**
 * 绘制item
 *
 * @param canvas
 * @param data  数据集
 * @param position 在data数据集中的位置
 * @param relative 相对中间item的位置,relative==0表示中间item,relative<0表示上(左)边的item,relative>0表示下(右)边的item
 * @param moveLength 中间item滚动的距离,moveLength<0则表示向上(右)滚动的距离,moveLength>0则表示向下(左)滚动的距离
 * @param top 当前绘制item的坐标,当垂直滚动时为顶部y的坐标;当水平滚动时为item最左边x的坐标
 */
 public abstract void drawItem(Canvas canvas, List<T> data, int position, int relative, float moveLength, float top);

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 super.onSizeChanged(w, h, oldw, oldh);
 reset();
 }

 private void reset() {
 if (mCenterPosition < 0) {
  mCenterPosition = mVisibleItemCount / 2;
 }

 if (mIsHorizontal) {
  mItemHeight = getMeasuredHeight();
  mItemWidth = getMeasuredWidth() / mVisibleItemCount;

  mCenterY = 0;
  mCenterX = mCenterPosition * mItemWidth;

  mItemSize = mItemWidth;
  mCenterPoint = mCenterX;
 } else {
  mItemHeight = getMeasuredHeight() / mVisibleItemCount;
  mItemWidth = getMeasuredWidth();

  mCenterY = mCenterPosition * mItemHeight;
  mCenterX = 0;

  mItemSize = mItemHeight;
  mCenterPoint = mCenterY;
 }

 if (mCenterItemBackground != null) {
  mCenterItemBackground.setBounds(mCenterX, mCenterY, mCenterX + mItemWidth, mCenterY + mItemHeight);
 }

 }

 @RequiresApi(api = Build.VERSION_CODES.FROYO)
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 if (mDisallowTouch) { // 不允许触摸
  return true;
 }

 if (mGestureDetector.onTouchEvent(event)) {
  return true;
 }

 switch (event.getActionMasked()) {
  case MotionEvent.ACTION_MOVE:

  if (mIsHorizontal) {
   if (Math.abs(event.getX() - mLastMoveX) < 0.1f) {
   return true;
   }
   mMoveLength += event.getX() - mLastMoveX;
  } else {
   if (Math.abs(event.getY() - mLastMoveY) < 0.1f) {
   return true;
   }
   mMoveLength += event.getY() - mLastMoveY;
  }
  mLastMoveY = event.getY();
  mLastMoveX = event.getX();
  checkCirculation();
  invalidate();
  break;
  case MotionEvent.ACTION_UP:
  mLastMoveY = event.getY();
  mLastMoveX = event.getX();
  moveToCenter();
  break;
 }
 return true;
 }

 /**
 * @param curr
 * @param end
 */
 private void computeScroll(int curr, int end, float rate) {
 if (rate < 1) { // 正在滚动
  if (mIsHorizontal) {
  // 可以把scroller看做模拟的触屏滑动操作,mLastScrollX为上次滑动的坐标
  mMoveLength = mMoveLength + curr - mLastScrollX;
  mLastScrollX = curr;
  } else {
  // 可以把scroller看做模拟的触屏滑动操作,mLastScrollY为上次滑动的坐标
  mMoveLength = mMoveLength + curr - mLastScrollY;
  mLastScrollY = curr;
  }
  checkCirculation();
  invalidate();
 } else { // 滚动完毕
  mIsMovingCenter = false;
  mLastScrollY = 0;
  mLastScrollX = 0;

  // 直接居中,不通过动画
  if (mMoveLength > 0) { //// 向下滑动
  if (mMoveLength < mItemSize / 2) {
   mMoveLength = 0;
  } else {
   mMoveLength = mItemSize;
  }
  } else {
  if (-mMoveLength < mItemSize / 2) {
   mMoveLength = 0;
  } else {
   mMoveLength = -mItemSize;
  }
  }
  checkCirculation();
  mMoveLength = 0;
  mLastScrollY = 0;
  mLastScrollX = 0;
  notifySelected(true);
  invalidate();
 }

 }

 @Override
 public void computeScroll() {
 if (mScroller.computeScrollOffset()) { // 正在滚动
  if (mIsHorizontal) {
  // 可以把scroller看做模拟的触屏滑动操作,mLastScrollX为上次滑动的坐标
  mMoveLength = mMoveLength + mScroller.getCurrX() - mLastScrollX;
  } else {
  // 可以把scroller看做模拟的触屏滑动操作,mLastScrollY为上次滑动的坐标
  mMoveLength = mMoveLength + mScroller.getCurrY() - mLastScrollY;
  }
  mLastScrollY = mScroller.getCurrY();
  mLastScrollX = mScroller.getCurrX();
  checkCirculation(); // 检测当前选中的item
  invalidate();
 } else { // 滚动完毕
  if (mIsFling) {
  mIsFling = false;
  moveToCenter(); // 滚动到中间位置
  } else if (mIsMovingCenter) { // 选择完成,回调给监听器
  mMoveLength = 0;
  mIsMovingCenter = false;
  mLastScrollY = 0;
  mLastScrollX = 0;
  notifySelected(true);
  }
 }
 }

 public void cancelScroll() {
 mLastScrollY = 0;
 mLastScrollX = 0;
 mIsFling = mIsMovingCenter = false;
 mScroller.abortAnimation();
 stopAutoScroll();
 }

 // 检测当前选择的item位置
 private void checkCirculation() {
 if (mMoveLength >= mItemSize) { // 向下滑动
  // 该次滚动距离中越过的item数量
  int span = (int) (mMoveLength / mItemSize);
  mSelected -= span;
  if (mSelected < 0) { // 滚动顶部,判断是否循环滚动
  if (mIsCirculation) {
   do {
   mSelected = mData.size() + mSelected;
   } while (mSelected < 0); // 当越过的item数量超过一圈时
   mMoveLength = (mMoveLength - mItemSize) % mItemSize;
  } else { // 非循环滚动
   mSelected = 0;
   mMoveLength = mItemSize;
   if (mIsFling) { // 停止惯性滑动,根据computeScroll()中的逻辑,下一步将调用moveToCenter()
   mScroller.forceFinished(true);
   }
   if (mIsMovingCenter) { // 移回中间位置
   scroll(mMoveLength, 0);
   }
  }
  } else {
  mMoveLength = (mMoveLength - mItemSize) % mItemSize;
  }

 } else if (mMoveLength <= -mItemSize) { // 向上滑动
  // 该次滚动距离中越过的item数量
  int span = (int) (-mMoveLength / mItemSize);
  mSelected += span;
  if (mSelected >= mData.size()) { // 滚动末尾,判断是否循环滚动
  if (mIsCirculation) {
   do {
   mSelected = mSelected - mData.size();
   } while (mSelected >= mData.size()); // 当越过的item数量超过一圈时
   mMoveLength = (mMoveLength + mItemSize) % mItemSize;
  } else { // 非循环滚动
   mSelected = mData.size() - 1;
   mMoveLength = -mItemSize;
   if (mIsFling) { // 停止惯性滑动,根据computeScroll()中的逻辑,下一步将调用moveToCenter()
   mScroller.forceFinished(true);
   }
   if (mIsMovingCenter) { // 移回中间位置
   scroll(mMoveLength, 0);
   }
  }
  } else {
  mMoveLength = (mMoveLength + mItemSize) % mItemSize;
  }
 }
 }

 // 移动到中间位置
 private void moveToCenter() {

 if (!mScroller.isFinished() || mIsFling || mMoveLength == 0) {
  return;
 }
 cancelScroll();

 // 向下滑动
 if (mMoveLength > 0) {
  if (mIsHorizontal) {
  if (mMoveLength < mItemWidth / 2) {
   scroll(mMoveLength, 0);
  } else {
   scroll(mMoveLength, mItemWidth);
  }
  } else {
  if (mMoveLength < mItemHeight / 2) {
   scroll(mMoveLength, 0);
  } else {
   scroll(mMoveLength, mItemHeight);
  }
  }
 } else {
  if (mIsHorizontal) {
  if (-mMoveLength < mItemWidth / 2) {
   scroll(mMoveLength, 0);
  } else {
   scroll(mMoveLength, -mItemWidth);
  }
  } else {
  if (-mMoveLength < mItemHeight / 2) {
   scroll(mMoveLength, 0);
  } else {
   scroll(mMoveLength, -mItemHeight);
  }
  }
 }
 }

 // 平滑滚动
 private void scroll(float from, int to) {
 if (mIsHorizontal) {
  mLastScrollX = (int) from;
  mIsMovingCenter = true;
  mScroller.startScroll((int) from, 0, 0, 0);
  mScroller.setFinalX(to);
 } else {
  mLastScrollY = (int) from;
  mIsMovingCenter = true;
  mScroller.startScroll(0, (int) from, 0, 0);
  mScroller.setFinalY(to);
 }
 invalidate();
 }

 // 惯性滑动,
 private void fling(float from, float vel) {
 if (mIsHorizontal) {
  mLastScrollX = (int) from;
  mIsFling = true;
  // 最多可以惯性滑动10个item
  mScroller.fling((int) from, 0, (int) vel, 0, -10 * mItemWidth,
   10 * mItemWidth, 0, 0);
 } else {
  mLastScrollY = (int) from;
  mIsFling = true;
  // 最多可以惯性滑动10个item
  mScroller.fling(0, (int) from, 0, (int) vel, 0, 0, -10 * mItemHeight,
   10 * mItemHeight);
 }
 invalidate();
 }

 private void notifySelected(final boolean trigger) {
 if (mListener != null) {
  // 告诉监听器选择完毕
  post(new Runnable() {
  @Override
  public void run() {
   if(mLastSelected != mSelected){
   if(trigger){
    mListener.onSelected(ScrollPickerView.this, mSelected);
   }

   }
   mLastSelected = mSelected;
  }
  });
 }
 }

 private boolean mIsAutoScrolling = false;
 private ValueAnimator mAutoScrollAnimator;
 private final static SlotInterpolator sAutoScrollInterpolator = new SlotInterpolator();

 /**
 * 自动滚动(必须设置为可循环滚动)
 *
 * @param position
 * @param duration
 * @param speed 每毫秒移动的像素点
 */
 @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public void autoScrollFast(final int position, long duration, float speed, final Interpolator interpolator) {
 if (mIsAutoScrolling || !mIsCirculation) {
  return;
 }
 cancelScroll();
 mIsAutoScrolling = true;

 int length = (int) (speed * duration);
 int circle = (int) (length * 1f / (mData.size() * mItemSize) + 0.5f); // 圈数
 circle = circle <= 0 ? 1 : circle;

 int aPlan = circle * (mData.size()) * mItemSize + (mSelected - position) * mItemSize;
 int bPlan = aPlan + (mData.size()) * mItemSize; // 多一圈
 // 让其尽量接近length
 final int end = Math.abs(length - aPlan) < Math.abs(length - bPlan) ? aPlan : bPlan;

 mAutoScrollAnimator.cancel();
 mAutoScrollAnimator.setIntValues(0, end);
 mAutoScrollAnimator.setInterpolator(interpolator);
 mAutoScrollAnimator.setDuration(duration);
 mAutoScrollAnimator.removeAllUpdateListeners();
 if (end != 0) { // itemHeight为0导致endy=0
  mAutoScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
   float rate = 0;
   rate = animation.getCurrentPlayTime() * 1f / animation.getDuration();
   computeScroll((int) animation.getAnimatedValue(), end, rate);
  }
  });
  mAutoScrollAnimator.removeAllListeners();
  mAutoScrollAnimator.addListener(new AnimatorListenerAdapter() {
  @Override
  public void onAnimationEnd(Animator animation) {
   super.onAnimationEnd(animation);
   mIsAutoScrolling = false;
  }
  });
  mAutoScrollAnimator.start();
 } else {
  computeScroll(end, end, 1);
  mIsAutoScrolling = false;
 }
 }

 /**
 * 自动滚动,默认速度为 0.6dp/ms
 *
 * @see ScrollPickerView#autoScrollFast(int, long, float, Interpolator)
 */
 @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public void autoScrollFast(final int position, long duration) {
 float speed = dip2px(0.6f);
 autoScrollFast(position, duration, speed, sAutoScrollInterpolator);
 }

 /**
 * 自动滚动
 *
 * @see ScrollPickerView#autoScrollFast(int, long, float, Interpolator)
 */
 @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public void autoScrollFast(final int position, long duration, float speed) {
 autoScrollFast(position, duration, speed, sAutoScrollInterpolator);
 }

 /**
 * 滚动到指定位置
 *
 * @param toPosition  需要滚动到的位置
 * @param duration  滚动时间
 * @param interpolator
 */
 @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public void autoScrollToPosition(int toPosition, long duration, final Interpolator interpolator) {
 toPosition = toPosition % mData.size();
 final int endY = (mSelected - toPosition) * mItemHeight;
 autoScrollTo(endY, duration, interpolator, false);
 }

 /**
 * @param endY   需要滚动到的位置
 * @param duration  滚动时间
 * @param interpolator
 * @param canIntercept 能否终止滚动,比如触摸屏幕终止滚动
 */
 @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 public void autoScrollTo(final int endY, long duration, final Interpolator interpolator, boolean canIntercept) {
 if (mIsAutoScrolling) {
  return;
 }
 final boolean temp = mDisallowTouch;
 mDisallowTouch = !canIntercept;
 mIsAutoScrolling = true;
 mAutoScrollAnimator.cancel();
 mAutoScrollAnimator.setIntValues(0, endY);
 mAutoScrollAnimator.setInterpolator(interpolator);
 mAutoScrollAnimator.setDuration(duration);
 mAutoScrollAnimator.removeAllUpdateListeners();
 mAutoScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
  float rate = 0;
  rate = animation.getCurrentPlayTime() * 1f / animation.getDuration();
  computeScroll((int) animation.getAnimatedValue(), endY, rate);
  }
 });
 mAutoScrollAnimator.removeAllListeners();
 mAutoScrollAnimator.addListener(new AnimatorListenerAdapter() {
  @Override
  public void onAnimationEnd(Animator animation) {
  super.onAnimationEnd(animation);
  mIsAutoScrolling = false;
  mDisallowTouch = temp;
  }
 });
 mAutoScrollAnimator.start();
 }

 /**
 * 停止自动滚动
 */
 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
 public void stopAutoScroll() {
 mIsAutoScrolling = false;
 mAutoScrollAnimator.cancel();
 }

 private static class SlotInterpolator implements Interpolator {
 @Override
 public float getInterpolation(float input) {
  return (float) (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
 }
 }

 /**
 * 快速滑动时,惯性滑动一段距离
 *
 * @author huangziwei
 */
 private class FlingOnGestureListener extends GestureDetector.SimpleOnGestureListener {

 private boolean mIsScrollingLastTime = false;

 public boolean onDown(MotionEvent e) {
  if (mDisallowInterceptTouch) { // 不允许父组件拦截事件
  ViewParent parent = getParent();
  if (parent != null) {
   parent.requestDisallowInterceptTouchEvent(true);
  }
  }
  mIsScrollingLastTime = isScrolling(); // 记录是否从滚动状态终止
  // 点击时取消所有滚动效果
  cancelScroll();
  mLastMoveY = e.getY();
  mLastMoveX = e.getX();
  return true;
 }

 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
    final float velocityY) {
  // 惯性滑动
  if (mIsInertiaScroll) {
  cancelScroll();
  if (mIsHorizontal) {
   fling(mMoveLength, velocityX);
  } else {
   fling(mMoveLength, velocityY);
  }
  }
  return true;
 }

 @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
 @Override
 public boolean onSingleTapUp(MotionEvent e) {
  mLastMoveY = e.getY();
  mLastMoveX = e.getX();
  float lastMove = 0;

  if (isHorizontal()) {
  mCenterPoint = mCenterX;
  lastMove = mLastMoveX;
  LogUtils.e("lastMove===",lastMove+"");
  LogUtils.e("mCenterPoint===",mCenterPoint+"");

  } else {
  mCenterPoint = mCenterY;
  lastMove = mLastMoveY;
  }
  if (mCanTap && !isScrolling() && !mIsScrollingLastTime) {
  if (lastMove >= mCenterPoint && lastMove <= mCenterPoint + mItemSize) {
   //performClick();
  } else if (lastMove < mCenterPoint) {
   int bs = (int)((mCenterPoint+mItemSize) - lastMove)/mItemSize;
   int move = bs*mItemSize;
   autoScrollTo(move, 150, sAutoScrollInterpolator, false);
  } else if (lastMove > mCenterPoint + mItemSize) {
   int bs = (int)((lastMove -mCenterPoint)/mItemWidth);
   int move = -bs*mItemSize;
   autoScrollTo(move, 150, sAutoScrollInterpolator, false);
  } else {
   moveToCenter();
  }
  } else {
  moveToCenter();
  }
  return true;
 }
 }

 public List<T> getData() {
 return mData;
 }

 public void setData(List<T> data) {
 if (data == null) {
  mData = new ArrayList<T>();
 } else {
  this.mData = data;
 }
 mSelected = mData.size() / 2;
 invalidate();
 }

 public T getSelectedItem() {
 return mData.get(mSelected);
 }

 public int getSelectedPosition() {
 return mSelected;
 }

 public void setSelectedPosition(int position,boolean trigger) {
 if (position < 0 || position > mData.size() - 1
  || position == mSelected) {
  return;
 }
 mSelected = position;
 invalidate();
 if (mListener != null) {
  notifySelected(trigger);
 }
 }

 public void setOnSelectedListener(OnSelectedListener listener) {
 mListener = listener;
 }

 public OnSelectedListener getListener() {
 return mListener;
 }

 public boolean isInertiaScroll() {
 return mIsInertiaScroll;
 }

 public void setInertiaScroll(boolean inertiaScroll) {
 this.mIsInertiaScroll = inertiaScroll;
 }

 public boolean isIsCirculation() {
 return mIsCirculation;
 }

 public void setIsCirculation(boolean isCirculation) {
 this.mIsCirculation = false;
 }

 public boolean isDisallowInterceptTouch() {
 return mDisallowInterceptTouch;
 }

 public int getVisibleItemCount() {
 return mVisibleItemCount;
 }

 public void setVisibleItemCount(int visibleItemCount) {
 mVisibleItemCount = visibleItemCount;
 reset();
 invalidate();
 }

 /**
 * 是否允许父元素拦截事件,设置true后可以保证在ScrollView下正常滚动
 */
 public void setDisallowInterceptTouch(boolean disallowInterceptTouch) {
 mDisallowInterceptTouch = disallowInterceptTouch;
 }

 public int getItemHeight() {
 return mItemHeight;
 }

 public int getItemWidth() {
 return mItemWidth;
 }

 /**
 * @return 当垂直滚动时,mItemSize = mItemHeight;水平滚动时,mItemSize = mItemWidth
 */
 public int getItemSize() {
 return mItemSize;
 }

 /**
 * @return 中间item的起始坐标x(不考虑偏移), 当垂直滚动时,x = mCenterPosition*mItemWidth
 */
 public int getCenterX() {
 return mCenterX;
 }

 /**
 * @return 中间item的起始坐标y(不考虑偏移), 当垂直滚动时,y= mCenterPosition*mItemHeight
 */
 public int getCenterY() {
 return mCenterY;
 }

 /**
 * @return 当垂直滚动时,mCenterPoint = mCenterY;水平滚动时,mCenterPoint = mCenterX
 */
 public int getCenterPoint() {
 return mCenterPoint;
 }

 public boolean isDisallowTouch() {
 return mDisallowTouch;
 }

 /**
 * 设置是否允许手动触摸滚动
 *
 * @param disallowTouch
 */
 public void setDisallowTouch(boolean disallowTouch) {
 mDisallowTouch = disallowTouch;
 }

 /**
 * 中间item的位置,0 <= centerPosition <= mVisibleItemCount
 *
 * @param centerPosition
 */
 public void setCenterPosition(int centerPosition) {
 if (centerPosition < 0) {
  mCenterPosition = 0;
 } else if (centerPosition >= mVisibleItemCount) {
  mCenterPosition = mVisibleItemCount - 1;
 } else {
  mCenterPosition = centerPosition;
 }
 mCenterY = mCenterPosition * mItemHeight;
 invalidate();
 }

 /**
 * 中间item的位置,默认为 mVisibleItemCount / 2
 *
 * @return
 */
 public int getCenterPosition() {
 return mCenterPosition;
 }

 public void setCenterItemBackground(Drawable centerItemBackground) {
 mCenterItemBackground = centerItemBackground;
 mCenterItemBackground.setBounds(mCenterX, mCenterY, mCenterX + mItemWidth, mCenterY + mItemHeight);
 invalidate();
 }

 public void setCenterItemBackground(int centerItemBackgroundColor) {
 mCenterItemBackground = new ColorDrawable(centerItemBackgroundColor);
 mCenterItemBackground.setBounds(mCenterX, mCenterY, mCenterX + mItemWidth, mCenterY + mItemHeight);
 invalidate();
 }

 public Drawable getCenterItemBackground() {
 return mCenterItemBackground;
 }

 public boolean isScrolling() {
 return mIsFling || mIsMovingCenter || mIsAutoScrolling;
 }

 public boolean isFling() {
 return mIsFling;
 }

 public boolean isMovingCenter() {
 return mIsMovingCenter;
 }

 public boolean isAutoScrolling() {
 return mIsAutoScrolling;
 }

 public boolean isCanTap() {
 return mCanTap;
 }

 /**
 * 设置 单击切换选项或触发点击监听器
 *
 * @param canTap
 */
 public void setCanTap(boolean canTap) {
 mCanTap = canTap;
 }

 public boolean isHorizontal() {
 return mIsHorizontal;
 }

 public boolean isVertical() {
 return !mIsHorizontal;
 }

 public void setHorizontal(boolean horizontal) {
 if (mIsHorizontal == horizontal) {
  return;
 }
 mIsHorizontal = horizontal;
 reset();
 if (mIsHorizontal) {
  mItemSize = mItemWidth;
 } else {
  mItemSize = mItemHeight;
 }
 invalidate();
 }

 public void setVertical(boolean vertical) {
 if (mIsHorizontal == !vertical) {
  return;
 }
 mIsHorizontal = !vertical;
 reset();
 if (mIsHorizontal) {
  mItemSize = mItemWidth;
 } else {
  mItemSize = mItemHeight;
 }
 invalidate();
 }

 public boolean isDrawAllItem() {
 return mDrawAllItem;
 }

 public void setDrawAllItem(boolean drawAllItem) {
 mDrawAllItem = drawAllItem;
 }

 /**
 * @author huangziwei
 */
 public interface OnSelectedListener {
 void onSelected(ScrollPickerView scrollPickerView, int position);
 }

 public int dip2px(float dipVlue) {
 DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
 float sDensity = metrics.density;
 return (int) (dipVlue * sDensity + 0.5F);
 }

 @Override
 public void setVisibility(int visibility) {
 super.setVisibility(visibility);
 if (visibility == VISIBLE) {
  moveToCenter();
 }
 }
}

ColorUtil 类

package com.demo.utils;

import android.graphics.Color;

/**
 * 颜色工具栏
 */
public class ColorUtil {

 /**
 * 计算渐变后的颜色
 *
 * @param startColor 开始颜色
 * @param endColor 结束颜色
 * @param rate 渐变率(0,1)
 * @return 渐变后的颜色,当rate=0时,返回startColor,当rate=1时返回endColor
 */
 public static int computeGradientColor(int startColor, int endColor, float rate) {
 if (rate < 0) {
  rate = 0;
 }
 if (rate > 1) {
  rate = 1;
 }

 int alpha = Color.alpha(endColor) - Color.alpha(startColor);
 int red = Color.red(endColor) - Color.red(startColor);
 int green = Color.green(endColor) - Color.green(startColor);
 int blue = Color.blue(endColor) - Color.blue(startColor);

 return Color.argb(
  Math.round(Color.alpha(startColor) + alpha * rate),
  Math.round(Color.red(startColor) + red * rate),
  Math.round(Color.green(startColor) + green * rate),
  Math.round(Color.blue(startColor) + blue * rate));
 }
}

调用

/**
 * 温度
*/
airTemperatureView = new AirTemperatureView(context);
 LinearLayout.LayoutParams airTemperatureView_Params = new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,Axis.scaleX(230));
 airTemperatureView_Params.setMargins(0,Axis.scaleX(100),0,0);
 bodyLayout.addView(airTemperatureView,airTemperatureView_Params);//父布局 addView()
 airTemperatureView.setOnTemperatureListener(new AirTemperatureView.TemperatureListener() {
 @Override
 public void setAirTemper(int temperature) {
 LogUtils.e("空调温度===",temperature+"");
 setTemperature(temperature);//网络请求方法
 }
});

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

时间: 2018-07-25

Android自定义控件实现带文字提示的SeekBar

1.写在前面 SeekBar控件在开发中还是比较常见的,比如音视频进度.音量调节等,但是原生控件有时还不能满足我们的需求,今天就来学习一下如何自定义SeekBar控件,本文主要实现了一个带文字指示器效果的SeekBar控件 看下最终效果: IndicatorSeekBar 2.实现 IndicatorSeekBar public class IndicatorSeekBar extends AppCompatSeekBar { // 画笔 private Paint mPaint; // 进度文

Android自定义控件ListView下拉刷新的代码

ListView在实际实用中,一般都会有下新刷新和上拉加载的动态效果,今天要学的就是如何自定义带下拉刷新的ListView. 原理解析:一般将有下拉刷新的listview分成四种不同的状态来进行不同的显示效果. 1.完成状态done:listview正常显示状态 2.下拉状态pull:listview正在下拉时的状态 3.释放状态release:listview下拉后松开的状态 4.更新状态refreshing:listview下拉后加载数据时的状态 实现步骤: 自定义CustomListVie

Android组合式自定义控件实现购物车加减商品操作

本文实例为大家分享了Android实现购物车加减商品操作的具体代码,供大家参考,具体内容如下 MainActivity.java public class MainActivity extends AppCompatActivity { private Addand mAddand; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setConte

Android自定义动画根据控件Y轴旋转动画(仿红包)

这里给正在学安卓的小白们分享一个动画吧,用处挺多,代码也不多,还望各位大佬不要打击. 进入正题,先看看效果 效果很炫酷很美好 好了 来看代码吧    该说的都在代码注释里面  这个不用多说 代码极其简单 //自定义一个类继承Animation(android.view.animation.Animation)抽象类 public class MyAnimation extends Animation { // 先定义成员变量 //X轴的中心坐标 int center_X; //Y轴的中心坐标 i

Android自定义控件的步骤

学习初衷:在工作实际开发过程中,原有的安卓控件已不能满足实际的功能需求,而且有些应用还需要一些独特的展示效果,这时就需要自定义控件来定制控件去满足我们的需求了. 自定义控件的步骤 步骤一:首先要新建一个类CustomView继承自View public class CustomView extends View{} 步骤二:添加构造器,用的是有AttributeSet参数的那个构造方法 public CustomView(Context context,AttributeSet attrs){

Android自定义日历滑动控件

本文实例为大家分享了Android自定义日历滑动控件的使用方法,供大家参考,具体内容如下 最近公司项目需要做这个需求,自己才疏学浅,总算能写出个大概来,遂在这里记录下来. 分析 先来分析一下: 首先,我们的需求是可以左右点击查看跳转到下一个月,中间的日历控件可以水平滚动选择日期,所以我们中间的日历控件用一个RecycleView来做,左右两位的为ImageVeiw. LRCalendarView 总体流程: 编写LRCalendarView的布局R.layout.calendar_view 新建

Android自定义控件实现不规则区域点击事件

本文实例为大家分享了Android实现不规则区域点击事件的具体代码,供大家参考,具体内容如下 先看看效果 对于上面的图形实现主要用到svg,通过解析svg获取不规则的图形,对于svg文件这个一般需要美工提供,不需要我们开发实现. 实现上面效果第一步是解析svg文件代码如下 package demo.zjd.com.taiwandemo.utils; import android.graphics.RectF; import android.util.Xml; import org.xmlpull

Android自定义图片轮播Banner控件使用解析

图片轮播控件,可以说是每个App基本上都会用到的.它可以用来动态的展示多个图片,之前写过两篇博客:实现ViewPager无限循环的方式一和实现ViewPager无限循环的方式二,在这两篇博客中,分析了两种实现ViewPager无限循环的原理,但是在使用的过程中,代码的解偶性很低,所以就使用自定义View的方式,实现无限循环的图片轮播的封装. 先看看效果: 功能特点 支持自定义宽高比例 支持自定义图片切换时间 支持自定义指示点的颜色 支持自定义指示点的背景色 支持自定义指示点的高度 支持是否显示指

Android自定义控件实现颜色选择器

ColorPickerView 是之前一个智能家居项目实战中所写的自定义控件,主要用于取得RGB 0~255范围的值,然后转换成十六进制0~FF的值,发送给网关控制RGB彩灯.参考的是网上一个朋友的源码写的,多的不说了,先看效果图 activity_mian.xml文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas

Android自定义弹窗提醒控件使用详解

Android中原生的Dialog弹窗提醒控件样式单一,有时候并不能满足我们的项目需求,而且一个工程里面有时候会在多处都用到弹窗提醒的功能,代码会出现大量的冗余,工作之余,就自己实现了这么一个弹窗提醒控件.自定义控件继承自我们的Dialog,样式自定义,弹窗中的文字可通过数组参数初始化,Item个数实现了动态添加,和数组长度一致.对话框底端可展示一个Item(如:确定)或两个Item(如:确定   取消),通过参数设置.废话不多说,直接上代码: 1.自定义对话框的背景样式,在res/values

Android消息个数提醒控件使用详解

前言 在QQ中有消息个数提醒的控件,虽然现在没用到,但是以后可能会用到,所以就实现它,也不难. 实现 效果图如下: 先贴源码了: public class TipNumberView extends TextView { private Paint mBgPaint ; PaintFlagsDrawFilter pfd; public TipNumberView(Context context, AttributeSet attrs) { super(context, attrs); //初始化

android水平循环滚动控件使用详解

本文实例为大家分享了android水平循环滚动控件的具体代码,供大家参考,具体内容如下 CycleScrollView.java package com.example.test; import android.content.Context; import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; import android.view.GestureDetector;

Android UI组件AppWidget控件入门详解

Widget引入 我们可以把Widget理解成放置在桌面上的小组件(挂件),有了Widget,我们可以很方便地直接在桌面上进行各种操作,例如播放音乐. 当我们长按桌面时,可以看到Widget选项,如下图所示: 点击上图中箭头处的widgets图标,会出现如下界面:(都是widget) 长按上图中的任意一个widget,就可以将其放到桌面上. Widget的使用 Widget的实现思路  (1)在AndroidManifest中声明AppWidget:  (2)在xml目录中定义AppWidget

Android 仿淘宝、京东商品详情页向上拖动查看图文详情控件DEMO详解

一.淘宝商品详情页效果 我们的效果 二.实现思路 使用两个scrollView,两个scrollView 竖直排列,通过自定义viewGroup来控制两个scrollView的竖直排列,以及滑动事件的处理.如下图 三.具体实现 1.继承viewGroup自定义布局View 重写onMeasure()和onLayout方法,在onLayout方法中完成对两个子ScrollView的竖直排列布局,代码如下: 布局文件: <RelativeLayout xmlns:android="http:/

Android仿京东淘宝自动无限循环轮播控件思路详解

在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于RelativeLayout,首先要考虑的就是自定义的控件需要扩展那些属性,把这些属性列出来.在这里是要实现类似于京东淘宝的无限轮播广告栏,那么首先想到的就是轮播的时长.轮播指示器的样式等等.我在这里列举了一些并且结合到了代码中. 1.扩展属性 (1)是否开启自动轮播的功能. (2)指示器的图形样式,一

Android 带清除功能的输入框控件实例详解

Android 带清除功能的输入框控件实例详解 今天,看到一个很好的自定义输入框控件,于是记录一下. 效果很好: 一,自定义一个类,名为ClearEditText package com.example.clearedittext; import android.content.Context; import android.graphics.drawable.Drawable; import android.text.Editable; import android.text.TextWatc

Android自定义播放器控件VideoView

介绍 最近要使用播放器做一个简单的视频播放功能,开始学习VideoView,在横竖屏切换的时候碰到了点麻烦,不过在查阅资料后总算是解决了.在写VideoView播放视频时候定义控制的代码全写在Actvity里了,写完一看我靠代码好乱,于是就写了个自定义的播放器控件,支持指定大小,可以横竖屏切换,手动左右滑动快进快退.好了,下面开始. 效果图有点卡,我也不知道为啥..... VideoView介绍 这个是我们实现视频播放最主要的控件,详细的介绍大家百度就去看,这里介绍几个常用的方法. 用于播放视频

android之SeekBar控件用法详解

MainActivity.java package com.example.mars_2400_seekbar; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBar; import android.support.v4.app.Fragment; import android.app.Activity; import android.os.Bundle; import a

Android自定义加载控件实现数据加载动画

本文实例为大家分享了Android自定义加载控件,第一次小人跑动的加载效果眼前一亮,相比传统的PrograssBar高大上不止一点,于是走起,自定义了控件LoadingView去实现动态效果,可直接在xml中使用,具体实现如下 package com.*****.*****.widget; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.util.