控件简介

UISegmentControl在IOS平台的App中非常常见,其控件如下图所示:

这种控件的主要作用是动态的更改界面的显示内容,一般应用于内容较多的界面,且分屏显示不同种类的内容。

在Android开发过程中,有时需要实现类似UISegmentControl的效果,这里我将自己的代码开源在github上了,命名为SegmentControlView,下面是实现的效果:

动态图片可点击如下链接:
https://github.com/Carbs0126/AndroidSegmentControlView

控件说明

SegmentControlView extends View

这个SegmentControlView是继承自View的,而非组合控件,因此实现起来虽然有点繁琐,但是灵活性反而比组合控件要高很多,并且可以加上过度效果等,且比组合控件更加轻量化。

控件特点

我实现的这个SegmentControlView具有如下特点:

1.SegmentControlView可设置与ViewPager联动,在segment切换时具有颜色渐变效果,类似微信。
2.可以自定义SegmentControlView的四个corner的半径。
3.自定义背景颜色与字体颜色、字体大小等等。
4.在xml中设置SegmentControlView中的多个titles,自动按照titles生成多个segment。
5.设置按下颜色与normal颜色的色值对比度。
6.具有AT_MOST的适配功能,即具有wrap_content模式
7.可以设置回调响应事件

使用方法

属性文件说明

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="SegmentControlView"><attr name="scv_BackgroundSelectedColor" format="reference|color" />//选中segment的背景颜色<attr name="scv_BackgroundNormalColor" format="reference|color" />//未选中segment的背景颜色<attr name="scv_TextSelectedColor" format="reference|color" />//选中segment的文字颜色<attr name="scv_TextNormalColor" format="reference|color" />//未选中segment的文字颜色<attr name="scv_FrameColor" format="reference|color" />//segment边框的颜色<attr name="scv_FrameWidth" format="reference|dimension" />//segment边框的宽度<attr name="scv_FrameCornerRadius" format="reference|dimension" />//segment四个圆角的半径大小<attr name="scv_TextSize" format="reference|dimension" />//文字大小<attr name="scv_TextArray" format="reference" />//string数组,每一个string都会填充到一个segment中<attr name="scv_SelectedIndex" format="reference|integer" />//默认选中的segment<attr name="scv_SegmentPaddingHorizontal" format="reference|dimension" />//每一个segment内部的水平padding<attr name="scv_SegmentPaddingVertical" format="reference|dimension" />每一个Segment的竖直方向的padding<attr name="scv_Gradient" format="reference|boolean" />//Segment改变时是否使用颜色渐变效果</declare-styleable></resources>

布局文件创建SegmentControlView

<cn.carbs.android.segmentcontrolview.library.SegmentControlViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:paddingLeft="10dp"android:paddingRight="10dp"app:scv_FrameCornerRadius="6dp"app:scv_FrameWidth="1dp"app:scv_Gradient="true"app:scv_SegmentPaddingVertical="5dp"app:scv_TextArray="@array/segment_control_arrays_0"/>

使用方法

dependencies {compile 'cn.carbs.android:SegmentControlView:1.0.0'
}
    segmentcontrolview.setOnSegmentChangedListener(new SegmentControlView.OnSegmentChangedListener() {@Overridepublic void onSegmentChanged(int newSelectedIndex) {if(viewpager != null){//change the second argument to true if you want the gradient effect when viewpager is changingviewpager.setCurrentItem(newSelectedIndex, false);//viewpager changing without animation}}});//set viewpager to change segment according to the state of viewpagersegmentcontrolview.setViewPager(viewpager);//set the selected index of segments initiativelysegmentcontrolview.setSelectedIndex();//set gradient effect if you wantsegmentcontrolview.setGradient(true);

项目地址:

https://github.com/Carbs0126/AndroidSegmentControlView

Git:

git clone https://github.com/Carbs0126/AndroidSegmentControlView.git

源码如下

package cn.carbs.android.segmentcontrolview.library;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v4.view.ViewPager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;import java.lang.reflect.Field;/*** an SegmentControlView inspired by the UISegmentControl on IOS platform.* this view has many interesting such as :*  1. set gradient effect when segment is changing by ViewPager if needed*  2. set the corners' radius*  3. set colors of texts and background*  4. set titles in xml resource file*  5. has pressed effect when finger touches this view, you can set the dark coefficient   * * Author   Carbs.Wang * Email    yeah0126#yeah.net*/
public class SegmentControlView extends View {/*** onSegmentChanged function will be triggered if segment changed*/public interface OnSegmentChangedListener{void onSegmentChanged(int newSelectedIndex);}private static final float TOUCHED_BACKGROUND_DARK_COEFFICIENT = 0.95F;private static final int COLOR_PRIMARY_NORMAL = 0XFFFFFFFF;private static final int COLOR_PRIMARY_SELECTED = 0XFF2CA99F;private static final int DEFAULT_COLOR_BACKGROUND_SELECTED = COLOR_PRIMARY_SELECTED;private static final int DEFAULT_COLOR_BACKGROUND_NORMAL = COLOR_PRIMARY_NORMAL;private static final int DEFAULT_COLOR_TEXT_SELECTED = COLOR_PRIMARY_NORMAL;private static final int DEFAULT_COLOR_TEXT_NORMAL = COLOR_PRIMARY_SELECTED;private static final int DEFAULT_COLOR_FRAME = COLOR_PRIMARY_SELECTED;private static final int DEFAULT_TEXT_SIZE_SP = 16;private static final int DEFAULT_FRAME_WIDTH_PX = 2;private static final int DEFAULT_FRAME_CORNER_RADIUS_PX = 0;private static final int DEFAULT_SELECTED_INDEX = 0;private static final int DEFAULT_SEGMENT_PADDING_HORIZONTAL = 16;private static final int DEFAULT_SEGMENT_PADDING_VERTICAL = 12;private static final boolean DEFAULT_IS_GRADIENT = false;private String[] mTexts = null;private int mColorBackgroundSelected = DEFAULT_COLOR_BACKGROUND_SELECTED;private int mColorBackgroundNormal = DEFAULT_COLOR_BACKGROUND_NORMAL;private int mColorTextSelected = DEFAULT_COLOR_TEXT_SELECTED;private int mColorTextNormal = DEFAULT_COLOR_TEXT_NORMAL;private int mColorFrame = DEFAULT_COLOR_FRAME;private int mFrameWidth = DEFAULT_FRAME_WIDTH_PX;private int mFrameCornerRadius = DEFAULT_FRAME_CORNER_RADIUS_PX;private int mTextSize = 0;private int mSelectedIndex = DEFAULT_SELECTED_INDEX;//used in wrap_content modeprivate int mSegmentPaddingHorizontal = DEFAULT_SEGMENT_PADDING_HORIZONTAL;private int mSegmentPaddingVertical = DEFAULT_SEGMENT_PADDING_VERTICAL;private boolean mIsGradient = DEFAULT_IS_GRADIENT;private OnSegmentChangedListener mOnSegmentChangedListener;private float unitWidth = 0;private Paint paintText;        //painter of the text private Paint paintBackground;  //painter of the backgroundprivate Paint paintFrame;       //painter of the frameprivate RectF rectF;private RectF rectFArc;private Path pathFrame;private float textCenterYOffset;private int preTouchedIndex = -1;private int curTouchedIndex = -1;private ViewPager viewPager;public SegmentControlView(Context context) {super(context);init();}public SegmentControlView(Context context, AttributeSet attrs) {super(context, attrs);initAttr(context, attrs);init();}public SegmentControlView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initAttr(context, attrs);init();}private void initAttr(Context context, AttributeSet attrs) {if (attrs == null) {return;}TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SegmentControlView);int n = a.getIndexCount();for (int i = 0; i < n; i++) {int attr = a.getIndex(i);if(attr == R.styleable.SegmentControlView_scv_BackgroundSelectedColor){mColorBackgroundSelected = a.getColor(attr, DEFAULT_COLOR_BACKGROUND_SELECTED);}else if(attr == R.styleable.SegmentControlView_scv_BackgroundNormalColor){mColorBackgroundNormal = a.getColor(attr, DEFAULT_COLOR_BACKGROUND_NORMAL);}else if(attr == R.styleable.SegmentControlView_scv_TextSelectedColor){mColorTextSelected = a.getColor(attr, DEFAULT_COLOR_TEXT_SELECTED);}else if(attr == R.styleable.SegmentControlView_scv_TextNormalColor){mColorTextNormal = a.getColor(attr, DEFAULT_COLOR_TEXT_NORMAL);}else if(attr == R.styleable.SegmentControlView_scv_FrameColor){mColorFrame = a.getColor(attr, DEFAULT_COLOR_FRAME);}else if(attr == R.styleable.SegmentControlView_scv_TextSize){mTextSize = a.getDimensionPixelSize(attr, sp2px(getContext(), DEFAULT_TEXT_SIZE_SP));}else if(attr == R.styleable.SegmentControlView_scv_TextArray){mTexts = convertCharSequenceToString(a.getTextArray(attr));}else if(attr == R.styleable.SegmentControlView_scv_FrameWidth){mFrameWidth = a.getDimensionPixelSize(attr, DEFAULT_FRAME_WIDTH_PX);}else if(attr == R.styleable.SegmentControlView_scv_FrameCornerRadius){mFrameCornerRadius = a.getDimensionPixelSize(attr, DEFAULT_FRAME_CORNER_RADIUS_PX);}else if(attr == R.styleable.SegmentControlView_scv_SelectedIndex){mSelectedIndex = a.getInteger(attr, DEFAULT_SELECTED_INDEX);}else if(attr == R.styleable.SegmentControlView_scv_SegmentPaddingHorizontal){mSegmentPaddingHorizontal = a.getDimensionPixelSize(attr, DEFAULT_SEGMENT_PADDING_HORIZONTAL);}else if(attr == R.styleable.SegmentControlView_scv_SegmentPaddingVertical){mSegmentPaddingVertical = a.getDimensionPixelSize(attr, DEFAULT_SEGMENT_PADDING_VERTICAL);}else if(attr == R.styleable.SegmentControlView_scv_Gradient){mIsGradient = a.getBoolean(attr, DEFAULT_IS_GRADIENT);}}a.recycle();}private void init(){rectF = new RectF();rectFArc = new RectF();pathFrame = new Path();if(mTextSize == 0)mTextSize = sp2px(getContext(), DEFAULT_TEXT_SIZE_SP);paintText = new Paint();paintText.setAntiAlias(true);paintText.setTextAlign(Paint.Align.CENTER);paintText.setTextSize(mTextSize);paintBackground = new Paint();paintBackground.setAntiAlias(true);paintBackground.setStyle(Paint.Style.FILL);paintFrame = new Paint();paintFrame.setAntiAlias(true);paintFrame.setStyle(Paint.Style.STROKE);paintFrame.setStrokeWidth(mFrameWidth);paintFrame.setColor(mColorFrame);textCenterYOffset = getTextCenterYOffset(paintText.getFontMetrics());this.setClickable(true);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(measureWidth(widthMeasureSpec, paintText), measureHeight(heightMeasureSpec, paintText));  }@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);rectF.left = getPaddingLeft();rectF.top = getPaddingTop();rectF.right = w - getPaddingRight();rectF.bottom = h - getPaddingBottom();float inset = (float)Math.ceil(mFrameWidth / 2);rectF.inset(inset, inset);if(mTexts!= null && mTexts.length > 0){unitWidth = rectF.width() / mTexts.length;}rectFArc.left = 0;rectFArc.top = 0;rectFArc.right = 2 * mFrameCornerRadius;rectFArc.bottom = 2 * mFrameCornerRadius;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if(!isStringArrayEmpty(mTexts)){drawBackgroundAndFrameAndText(canvas);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {preTouchedIndex = curTouchedIndex;switch(event.getAction()){case MotionEvent.ACTION_DOWN:curTouchedIndex = getTouchedIndex(event.getX(), event.getY());if(preTouchedIndex != curTouchedIndex){invalidate();}break;case MotionEvent.ACTION_MOVE:curTouchedIndex = getTouchedIndex(event.getX(), event.getY());if(preTouchedIndex != curTouchedIndex){invalidate();}break;case MotionEvent.ACTION_UP:curTouchedIndex = getTouchedIndex(event.getX(), event.getY());if(curTouchedIndex != -1){if(mOnSegmentChangedListener != null && mSelectedIndex != curTouchedIndex){mOnSegmentChangedListener.onSegmentChanged(curTouchedIndex);}mSelectedIndex = curTouchedIndex;}curTouchedIndex = -1;if(mIsGradient && checkViewPagerOnPageChangeListener(this.viewPager)){}else{invalidate();}break;case MotionEvent.ACTION_CANCEL:curTouchedIndex = -1;invalidate();break;}return super.onTouchEvent(event);}public void setTextSize(int textSize){if(this.mTextSize != textSize){this.mTextSize = textSize;paintText.setTextSize(textSize);textCenterYOffset = getTextCenterYOffset(paintText.getFontMetrics());requestLayout();invalidate();}}public int getSelectedIndex(){return mSelectedIndex;}public void setSelectedIndex(int selectedIndex){if(mSelectedIndex != selectedIndex){mSelectedIndex = selectedIndex;if(mOnSegmentChangedListener != null){mOnSegmentChangedListener.onSegmentChanged(mSelectedIndex);}
//          invalidate();if(mIsGradient && checkViewPagerOnPageChangeListener(this.viewPager)){}else{invalidate();}}}public void setTextColor(int textColorNormal, int textColorSelected){this.mColorTextNormal = textColorNormal;this.mColorTextSelected = textColorSelected;invalidate();}public void setBackgroundColor(int backgroundColorNormal, int backgroundColorSelected){this.mColorBackgroundNormal = backgroundColorNormal;this.mColorBackgroundSelected = backgroundColorSelected;invalidate();}public void setFrameColor(int frameColor){this.mColorFrame = frameColor;invalidate();}public void setFrameWidth(int frameWidth){this.mFrameWidth = frameWidth;requestLayout();invalidate();}public void setTexts(String[] texts){assertTextsValid(texts);if(texts == null || texts.length < 2){throw new IllegalArgumentException("SegmentControlView's content text array'length should larger than 1");}if(checkIfEqual(this.mTexts, texts)){return;}this.mTexts = texts;unitWidth = rectF.width() / texts.length;requestLayout();invalidate();}public int getCount(){if(mTexts == null) return 0;return mTexts.length;}/*** setViewPager(viewpager) to response to the change of ViewPager* @param viewPager the viewPager you want segmentcontrolview to respond with*/public void setViewPager(ViewPager viewPager) {this.viewPager = viewPager;if (viewPager != null) {viewPager.setOnPageChangeListener(new InternalViewPagerListener());}}/*** set if this view has the Gradient effect when segment changed* @param gradient set if you want gradient effect*/public void setGradient(boolean gradient){if(mIsGradient != gradient){mIsGradient = gradient;}}public boolean getGradient(){return mIsGradient;}/*** when segment changed, * mOnSegmentChangedListener.onSegmentChanged(newSelectedIndex) will be triggered* @param listener OnSegmentChangedListener*/public void setOnSegmentChangedListener(OnSegmentChangedListener listener){mOnSegmentChangedListener = listener;}public void update(){invalidate();}private float getTextCenterYOffset(Paint.FontMetrics fontMetrics){if(fontMetrics == null) return 0;return Math.abs(fontMetrics.top + fontMetrics.bottom)/2;}private String[] convertCharSequenceToString(CharSequence[] csArray){if(csArray == null) return null;String[] sArray = new String[csArray.length];for(int i = 0; i < csArray.length; i++){sArray[i] = csArray[i].toString();}return sArray;}private void assertTextsValid(String[] texts){if(texts == null || texts.length < 2){throw new IllegalArgumentException("SegmentControlView's content text array'length should larger than 1");}}private boolean checkViewPagerOnPageChangeListener(ViewPager viewPager){if(viewPager == null) return false;Field field = null;try {field = ViewPager.class.getDeclaredField("mOnPageChangeListener");if(field == null) return false;field.setAccessible(true);Object o = field.get(viewPager);if(o != null && o instanceof InternalViewPagerListener){return true;}} catch (Exception e) {return false;}return false;}private int getTouchedIndex(float x, float y){if(!rectF.contains(x, y)){return -1;}for(int i = 0; i < mTexts.length; i++){if(rectF.left + i * unitWidth <= x && x < rectF.left + (i + 1) * unitWidth){return i;}}return -1;}private boolean checkIfEqual(String[] a, String[] b){if(a == null && b == null){return true;}if(a != null){if(b == null){return false;}if(a.length != b.length){return false;}for(int i = 0; i < a.length; i++){if(a[i] == null && b[i] == null){continue;}if(a[i] != null && a[i].equals(b[i])){continue;}else{return false;}}return true;}return false;}private int measureWidth(int measureSpec, Paint paint) {  int result = 0;  int specMode = MeasureSpec.getMode(measureSpec);  int specSize = MeasureSpec.getSize(measureSpec);  if (specMode == MeasureSpec.EXACTLY) {  result = specSize;} else {  int maxWidth = 0;int maxWidthItem = getMaxWidthOfTextArray(mTexts, paint);maxWidth = (maxWidthItem + 2 * mSegmentPaddingHorizontal + 2 * mFrameWidth) * mTexts.length;if(maxWidth < 2 * mFrameCornerRadius){maxWidth = 2 * mFrameCornerRadius;}result = this.getPaddingLeft() + this.getPaddingRight() + maxWidth;//MeasureSpec.UNSPECIFIEDif (specMode == MeasureSpec.AT_MOST) {result = Math.min(result, specSize);  }}return result;  }  private int measureHeight(int measureSpec, Paint paint) {  int result = 0;  int specMode = MeasureSpec.getMode(measureSpec);  int specSize = MeasureSpec.getSize(measureSpec);  if (specMode == MeasureSpec.EXACTLY) {  result = specSize;  } else {  int maxHeight = 0;int maxHeightItem = getMaxHeightOfTextArray(mTexts, paint);maxHeight = maxHeightItem + 2 * mSegmentPaddingVertical + 2 * mFrameWidth;if(maxHeight < 2 * mFrameCornerRadius){maxHeight = 2 * mFrameCornerRadius;}result = this.getPaddingTop() + this.getPaddingBottom() + maxHeight;//MeasureSpec.UNSPECIFIEDif (specMode == MeasureSpec.AT_MOST) {  result = Math.min(result, specSize);  }  }  return result;}private int getMaxWidthOfTextArray(String[] array, Paint paint){if(array == null){return 0;}int maxWidth = 0;for(String item : array){if(item != null){int itemWidth = getTextWidth(item, paint);maxWidth = Math.max(itemWidth, maxWidth);}}return maxWidth;}private int getMaxHeightOfTextArray(String[] array, Paint paint){if(array == null){return 0;}int maxHeight = 0;for(String item : array){if(item != null){int itemHeight = getTextHeight(item, paint);maxHeight = Math.max(itemHeight, maxHeight);}}return maxHeight;}private void drawBackgroundAndFrameAndText(Canvas canvas){int curBackgroundColor = 0;int curTextColor = 0;for(int i = 0; i < mTexts.length; i++){float left = rectF.left + unitWidth * i;pathFrame.reset();if(i == 0){pathFrame.moveTo(rectF.left, rectF.top + mFrameCornerRadius);rectFArc.offsetTo(rectF.left, rectF.top);pathFrame.arcTo(rectFArc, 180, 90);pathFrame.lineTo(rectF.left + unitWidth, rectF.top);pathFrame.lineTo(rectF.left + unitWidth, rectF.bottom);pathFrame.lineTo(rectF.left + mFrameCornerRadius, rectF.bottom);rectFArc.offsetTo(rectF.left, rectF.bottom - 2 * mFrameCornerRadius);pathFrame.arcTo(rectFArc, 90, 90);}else if(i == (mTexts.length - 1)){pathFrame.moveTo(rectF.left + i * unitWidth, rectF.top);pathFrame.lineTo(rectF.right - mFrameCornerRadius, rectF.top);rectFArc.offsetTo(rectF.right - 2 * mFrameCornerRadius, rectF.top);pathFrame.arcTo(rectFArc, 270, 90);pathFrame.lineTo(rectF.right, rectF.bottom - mFrameCornerRadius);rectFArc.offsetTo(rectF.right - 2 * mFrameCornerRadius, rectF.bottom - 2 * mFrameCornerRadius);pathFrame.arcTo(rectFArc, 0, 90);pathFrame.lineTo(rectF.left + i * unitWidth, rectF.bottom);}else{pathFrame.moveTo(left, rectF.top);pathFrame.lineTo(left + unitWidth, rectF.top);pathFrame.lineTo(left + unitWidth, rectF.bottom);pathFrame.lineTo(left, rectF.bottom);}pathFrame.close();if(!mIsGradient){if(i == mSelectedIndex){curBackgroundColor = mColorBackgroundSelected;curTextColor = mColorTextSelected;}else{curBackgroundColor = mColorBackgroundNormal;curTextColor = mColorTextNormal;}}if(mIsGradient){if(viewPagerPositionOffset != 0f){if(i == viewPagerPosition){curBackgroundColor = getEvaluateColor(viewPagerPositionOffset, mColorBackgroundSelected, mColorBackgroundNormal);curTextColor = getEvaluateColor(viewPagerPositionOffset, mColorTextSelected, mColorTextNormal);}else if(i == viewPagerPosition + 1){curBackgroundColor = getEvaluateColor(viewPagerPositionOffset, mColorBackgroundNormal, mColorBackgroundSelected);curTextColor = getEvaluateColor(viewPagerPositionOffset, mColorTextNormal, mColorTextSelected);}else{curBackgroundColor = mColorBackgroundNormal;curTextColor = mColorTextNormal;}}else{if(i == mSelectedIndex){curBackgroundColor = mColorBackgroundSelected;curTextColor = mColorTextSelected;}else{curBackgroundColor = mColorBackgroundNormal;curTextColor = mColorTextNormal;}}}paintBackground.setColor(curBackgroundColor);if(curTouchedIndex == i){paintBackground.setColor(getDarkColor(curBackgroundColor, TOUCHED_BACKGROUND_DARK_COEFFICIENT));}canvas.drawPath(pathFrame, paintBackground);canvas.drawPath(pathFrame, paintFrame);paintText.setColor(curTextColor);canvas.drawText(mTexts[i], left + unitWidth / 2,rectF.centerY() + textCenterYOffset, paintText);}}private int viewPagerPosition = -1;private float viewPagerPositionOffset = 0f;private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {if(mIsGradient){mSelectedIndex = position;viewPagerPosition = position;viewPagerPositionOffset = positionOffset;invalidate();}}@Overridepublic void onPageScrollStateChanged(int state) {}@Overridepublic void onPageSelected(int position) {if(mIsGradient){}else{SegmentControlView.this.setSelectedIndex(position);}}}private int getDarkColor(int color, float darkCoefficient){int a = (color & 0xff000000) >>> 24;int r = (color & 0x00ff0000) >>> 16;int g = (color & 0x0000ff00) >>> 8;int b = (color & 0x000000ff) >>> 0;r = (int)(r * darkCoefficient);g = (int)(g * darkCoefficient);b = (int)(b * darkCoefficient);return a << 24 | r << 16 | g << 8 | b;}private int getEvaluateColor(float fraction, int startColor, int endColor){int a, r, g, b;int sA = (startColor & 0xff000000) >>> 24;int sR = (startColor & 0x00ff0000) >>> 16;int sG = (startColor & 0x0000ff00) >>> 8;int sB = (startColor & 0x000000ff) >>> 0;int eA = (endColor & 0xff000000) >>> 24;int eR = (endColor & 0x00ff0000) >>> 16;int eG = (endColor & 0x0000ff00) >>> 8;int eB = (endColor & 0x000000ff) >>> 0;a = (int)(sA + (eA - sA) * fraction);r = (int)(sR + (eR - sR) * fraction);g = (int)(sG + (eG - sG) * fraction);b = (int)(sB + (eB - sB) * fraction);return a << 24 | r << 16 | g << 8 | b;}private boolean isStringArrayEmpty(String[] array){return (array == null || array.length == 0);}private static int sp2px(Context context, float spValue) {  final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;  return (int) (spValue * fontScale + 0.5f);  } private int getTextWidth(String text, Paint paint){if(!TextUtils.isEmpty(text)){return (int)(paint.measureText(text) + 0.5f);}return -1;}private int getTextHeight(String text, Paint paint){if(!TextUtils.isEmpty(text)){Rect textBounds = new Rect();paint.getTextBounds(text, 0, text.length(), textBounds);return textBounds.height();}return -1;}
}

自定义控件之AndroidSegmentControlView,仿IOS平台UISegmentControlView,继承自View相关推荐

  1. Android仿IOS解锁密码界面-自定义view系列(6)

    Android仿IOS解锁密码界面-自定义view系列 功能简介 主要实现步骤-具体内容看github项目里的代码 xml相关属性设置 Android Studio 代码 Android技术生活交流 ...

  2. Android 自定义控件之 SwitchButton(仿 iOS 开关)

    上图中的按钮是 iOS 中的自带的开关控件,Android 也有很多优秀的仿这个控件的开源库,自己也是模仿着实现了一下,下面记录一下实现过程. 1 思路 首先还是来进行分解动作,从静态样子来看,这个开 ...

  3. Android自定义控件实战——实现仿IOS下拉刷新上拉加载 PullToRefreshLayout

    下拉刷新控件,网上有很多版本,有自定义Layout布局的,也有封装控件的,各种实现方式的都有.但是很少有人告诉你具体如何实现的,今天我们就来一步步实现自己封装的 PullToRefreshLayout ...

  4. Android安卓仿IOS音量调节-自定义view系列(4)

    Android安卓仿IOS音量调节-自定义view系列 功能简介 主要实现步骤 xml相关属性设置 java代码 Android技术生活交流 更多其他页面-自定义View-实用功能合集:点击查看 Gi ...

  5. 【Android自定义控件】仿IOS风格的搜索框

    iOS很多控件的设计都是很值得借鉴的存在,作为移动开发的初学者,我们可以把这种模仿等同于学画.练字时为铸就基础的临摹行为.达者为师,努力学习别人的优点吧.  这里是仿IOS搜索框风格的自定义控件,引用 ...

  6. Android8.1 MTK平台 增加三指截屏(仿IOS左下角显示缩略图点击放大显示)

    效果图 修改后动画如下 系统原动画如下 三指截屏 PhoneWindowManager 同级目录下的 SystemGesturesPointerEventListener.java 主要负责处理界面的 ...

  7. [纪录]仿IOS滚轮效果(竖直滑动选择器)

    今天想做一个类似这样的一个效果,可是UI的模板是参考IOS做的,于是就各种百度各种搜,最后让我找到了一个仿IOS滚轮的一个Demo,稍微研究了一下,发上来,大家一起学习,以后也方便我查看,就不用再去百 ...

  8. Android高仿IOS和QQ的弹出对话框

    我们知道Android中其实并不提供圆形的东西,像Button,TextView,EditView等等都是没有弧形元素在里面(看看这些控件的属性就知道了).而很多时候我们的程序中又需要用到这样有弧形元 ...

  9. UE 手游在 iOS 平台运行时内存占用太高?试试这样着手优化

    性能优化,对游戏开发来说是一个需要不断钻研的课题,性能越好,游戏才会运行的更加顺畅,玩家的体验感才会更好.腾讯游戏学院专家.游戏客户端开发 Leonn,将和大家分享 UE 手游在 iOS 平台上的内存 ...

最新文章

  1. ABP中的Filter(下)
  2. 【Linux】【服务器】 CentOS7下安装MySQL(版本8.0)详细过程步骤
  3. GitHub基本使用
  4. 将一个数字划分成树状
  5. java input是什么意思_java中的【...】表示什么意思
  6. C#中ToString格式大全
  7. linux ora 27125,ORA-27125 unable to create shared memory segment | 信春哥,系统稳,闭眼上线不回滚!...
  8. 剑指offer 面试题64. 求1+2+…+n
  9. RocketMQ使用mmap - TODO
  10. AI 重塑 IT 的 5 种方式
  11. 【C++】将(数组)数据写入csv文件
  12. 计算机word宿舍管理软件,【UML课程设计】宿舍管理系统设计(WORD完整版).doc
  13. C语言求解一元二次方程
  14. 修改FTP和MSTSC默认端口号
  15. COB--COF--COG--TAB--TCP
  16. ROS2 spin_some, spin_once, and spin_until_future的不同地方
  17. php医疗管理系统(医院患者就诊档案管理系统)源码
  18. python少儿编程面试经验_编程猫少儿编程南京奥体中心
  19. egg开发笔记(五)egg使用egg-sequelize需要注意的事项
  20. 部分关于需求分析和软件构架的书籍

热门文章

  1. Sublime Text 3 安装教程(windows 10)
  2. IO流 序列化反序列化 Properties 缓冲流 字节流 字符流
  3. 学软件开发前景好吗?
  4. C++中for循环语句简析
  5. 网络安全观察DDoS 威胁
  6. iOS-百度地图聚合
  7. 文献管理软件Mendeley使用技法
  8. Leetcode 875. 爱吃香蕉的珂珂
  9. 基于JSPatch的iOS应用线上Bug的即时修复方案,附源码.
  10. “低钾本身就是一个不健康的状态