充电桩app代码

IndexBar.java 14KB

    package com.electric.chargingpile.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import androidx.recyclerview.widget.LinearLayoutManager; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import com.electric.chargingpile.R; import com.electric.chargingpile.data.BaseIndexPinyinBean; import com.electric.chargingpile.helper.IIndexBarDataHelper; import com.electric.chargingpile.helper.IndexBarDataHelperImpl; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 介绍:索引右侧边栏 * 作者:zhangxutong * 邮箱:mcxtzhang@163.com * CSDN:http://blog.csdn.net/zxt0601 * 时间: 16/09/04. */ public class IndexBar extends View { private static final String TAG = "zxt/IndexBar"; //#在最后面(默认的数据源) public static String[] INDEX_STRING = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#"}; //是否需要根据实际的数据来生成索引数据源(例如 只有 A B C 三种tag,那么索引栏就 A B C 三项) private boolean isNeedRealIndex; //索引数据源 private List<String> mIndexDatas; //View的宽高 private int mWidth, mHeight; //每个index区域的高度 private int mGapHeight; private Paint mPaint; //手指按下时的背景色 private int mPressedBackground; //以下是帮助类 //汉语->拼音,拼音->tag private IIndexBarDataHelper mDataHelper; //以下边变量是外部set进来的 private TextView mPressedShowTextView;//用于特写显示正在被触摸的index值 private boolean isSourceDatasAlreadySorted;//源数据 已经有序? private List<? extends BaseIndexPinyinBean> mSourceDatas;//Adapter的数据源 private LinearLayoutManager mLayoutManager; private int mHeaderViewCount = 0; public IndexBar(Context context) { this(context, null); } public IndexBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public IndexBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr); } public int getHeaderViewCount() { return mHeaderViewCount; } /** * 设置Headerview的Count * * @param headerViewCount * @return */ public IndexBar setHeaderViewCount(int headerViewCount) { mHeaderViewCount = headerViewCount; return this; } public boolean isSourceDatasAlreadySorted() { return isSourceDatasAlreadySorted; } /** * 源数据 是否已经有序 * * @param sourceDatasAlreadySorted * @return */ public IndexBar setSourceDatasAlreadySorted(boolean sourceDatasAlreadySorted) { isSourceDatasAlreadySorted = sourceDatasAlreadySorted; return this; } public IIndexBarDataHelper getDataHelper() { return mDataHelper; } /** * 设置数据源帮助类 * * @param dataHelper * @return */ public IndexBar setDataHelper(IIndexBarDataHelper dataHelper) { mDataHelper = dataHelper; return this; } private void init(Context context, AttributeSet attrs, int defStyleAttr) { int textSize = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics());//默认的TextSize mPressedBackground = Color.BLACK;//默认按下是纯黑色 // TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,R.styleable.in, defStyleAttr, 0); TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.IndexBar, defStyleAttr, 0); int n = typedArray.getIndexCount(); for (int i = 0; i < n; i++) { int attr = typedArray.getIndex(i); //modify 2016 09 07 :如果引用成AndroidLib 资源都不是常量,无法使用switch case if (attr == R.styleable.IndexBar_indexBarTextSize) { textSize = typedArray.getDimensionPixelSize(attr, textSize); } else if (attr == R.styleable.IndexBar_indexBarPressBackground) { mPressedBackground = typedArray.getColor(attr, mPressedBackground); } } typedArray.recycle(); initIndexDatas(); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setTextSize(textSize); mPaint.setColor(getResources().getColor(R.color.lvse)); //设置index触摸监听器 setmOnIndexPressedListener(new onIndexPressedListener() { @Override public void onIndexPressed(int index, String text) { if (mPressedShowTextView != null) { //显示hintTexView mPressedShowTextView.setVisibility(View.VISIBLE); mPressedShowTextView.setText(text); } //滑动Rv if (mLayoutManager != null) { int position = getPosByTag(text); if (position != -1) { mLayoutManager.scrollToPositionWithOffset(position, 0); } } } @Override public void onMotionEventEnd() { //隐藏hintTextView if (mPressedShowTextView != null) { mPressedShowTextView.setVisibility(View.GONE); } } }); mDataHelper = new IndexBarDataHelperImpl(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //取出宽高的MeasureSpec Mode 和Size int wMode = MeasureSpec.getMode(widthMeasureSpec); int wSize = MeasureSpec.getSize(widthMeasureSpec); int hMode = MeasureSpec.getMode(heightMeasureSpec); int hSize = MeasureSpec.getSize(heightMeasureSpec); int measureWidth = 0, measureHeight = 0;//最终测量出来的宽高 //得到合适宽度: Rect indexBounds = new Rect();//存放每个绘制的index的Rect区域 String index;//每个要绘制的index内容 for (int i = 0; i < mIndexDatas.size(); i++) { index = mIndexDatas.get(i); mPaint.getTextBounds(index, 0, index.length(), indexBounds);//测量计算文字所在矩形,可以得到宽高 measureWidth = Math.max(indexBounds.width(), measureWidth);//循环结束后,得到index的最大宽度 measureHeight = Math.max(indexBounds.height(), measureHeight);//循环结束后,得到index的最大高度,然后*size } measureHeight *= mIndexDatas.size(); switch (wMode) { case MeasureSpec.EXACTLY: measureWidth = wSize; break; case MeasureSpec.AT_MOST: measureWidth = Math.min(measureWidth, wSize);//wSize此时是父控件能给子View分配的最大空间 break; case MeasureSpec.UNSPECIFIED: break; } //得到合适的高度: switch (hMode) { case MeasureSpec.EXACTLY: measureHeight = hSize; break; case MeasureSpec.AT_MOST: measureHeight = Math.min(measureHeight, hSize);//wSize此时是父控件能给子View分配的最大空间 break; case MeasureSpec.UNSPECIFIED: break; } setMeasuredDimension(measureWidth, measureHeight); } @Override protected void onDraw(Canvas canvas) { int t = getPaddingTop();//top的基准点(支持padding) String index;//每个要绘制的index内容 for (int i = 0; i < mIndexDatas.size(); i++) { index = mIndexDatas.get(i); Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();//获得画笔的FontMetrics,用来计算baseLine。因为drawText的y坐标,代表的是绘制的文字的baseLine的位置 int baseline = (int) ((mGapHeight - fontMetrics.bottom - fontMetrics.top) / 2);//计算出在每格index区域,竖直居中的baseLine值 canvas.drawText(index, mWidth / 2 - mPaint.measureText(index) / 2, t + mGapHeight * i + baseline, mPaint);//调用drawText,居中显示绘制index } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: setBackgroundColor(mPressedBackground);//手指按下时背景变色 //注意这里没有break,因为down时,也要计算落点 回调监听器 case MotionEvent.ACTION_MOVE: float y = event.getY(); //通过计算判断落点在哪个区域: int pressI = (int) ((y - getPaddingTop()) / mGapHeight); //边界处理(在手指move时,有可能已经移出边界,防止越界) if (pressI < 0) { pressI = 0; } else if (pressI >= mIndexDatas.size()) { pressI = mIndexDatas.size() - 1; } //回调监听器 if (null != mOnIndexPressedListener && pressI > -1 && pressI < mIndexDatas.size()) { mOnIndexPressedListener.onIndexPressed(pressI, mIndexDatas.get(pressI)); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: default: setBackgroundResource(android.R.color.transparent);//手指抬起时背景恢复透明 //回调监听器 if (null != mOnIndexPressedListener) { mOnIndexPressedListener.onMotionEventEnd(); } break; } return true; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; //add by zhangxutong 2016 09 08 :解决源数据为空 或者size为0的情况, if (null == mIndexDatas || mIndexDatas.isEmpty()) { return; } computeGapHeight(); } /** * 当前被按下的index的监听器 */ public interface onIndexPressedListener { void onIndexPressed(int index, String text);//当某个Index被按下 void onMotionEventEnd();//当触摸事件结束(UP CANCEL) } private onIndexPressedListener mOnIndexPressedListener; public onIndexPressedListener getmOnIndexPressedListener() { return mOnIndexPressedListener; } public void setmOnIndexPressedListener(onIndexPressedListener mOnIndexPressedListener) { this.mOnIndexPressedListener = mOnIndexPressedListener; } /** * 显示当前被按下的index的TextView * * @return */ public IndexBar setmPressedShowTextView(TextView mPressedShowTextView) { this.mPressedShowTextView = mPressedShowTextView; return this; } public IndexBar setmLayoutManager(LinearLayoutManager mLayoutManager) { this.mLayoutManager = mLayoutManager; return this; } /** * 一定要在设置数据源{@link #setmSourceDatas(List)}之前调用 * * @param needRealIndex * @return */ public IndexBar setNeedRealIndex(boolean needRealIndex) { isNeedRealIndex = needRealIndex; initIndexDatas(); return this; } private void initIndexDatas() { if (isNeedRealIndex) { mIndexDatas = new ArrayList<>(); } else { mIndexDatas = Arrays.asList(INDEX_STRING); } } public IndexBar setmSourceDatas(List<? extends BaseIndexPinyinBean> mSourceDatas) { this.mSourceDatas = mSourceDatas; initSourceDatas();//对数据源进行初始化 return this; } /** * 初始化原始数据源,并取出索引数据源 * * @return */ private void initSourceDatas() { //add by zhangxutong 2016 09 08 :解决源数据为空 或者size为0的情况, if (null == mSourceDatas || mSourceDatas.isEmpty()) { return; } if (!isSourceDatasAlreadySorted) { //排序sourceDatas mDataHelper.sortSourceDatas(mSourceDatas); } else { //汉语->拼音 mDataHelper.convert(mSourceDatas); //拼音->tag mDataHelper.fillInexTag(mSourceDatas); } if (isNeedRealIndex) { mDataHelper.getSortedIndexDatas(mSourceDatas, mIndexDatas); computeGapHeight(); } //sortData(); } /** * 以下情况调用: * 1 在数据源改变 * 2 控件size改变时 * 计算gapHeight */ private void computeGapHeight() { mGapHeight = (mHeight - getPaddingTop() - getPaddingBottom()) / mIndexDatas.size(); } /** * 对数据源排序 */ private void sortData() { } /** * 根据传入的pos返回tag * * @param tag * @return */ private int getPosByTag(String tag) { //add by zhangxutong 2016 09 08 :解决源数据为空 或者size为0的情况, if (null == mSourceDatas || mSourceDatas.isEmpty()) { return -1; } if (TextUtils.isEmpty(tag)) { return -1; } for (int i = 0; i < mSourceDatas.size(); i++) { if (tag.equals(mSourceDatas.get(i).getBaseIndexTag())) { return i + getHeaderViewCount(); } } return -1; } }