Android PickerScrollView滑动选择控件使用方法详解

Hazel ·
更新时间:2024-09-20
· 834 次阅读

本文实例为大家分享了Android PickerScrollView滑动选择控件的具体使用代码,供大家参考,具体内容如下

先看一下效果图

1.SelectBean模拟假数据

public class SelectBean {     /**      * ret : 0      * msg : succes      * datas : [{"ID":"0","categoryName":"本人","state":"1"},{"ID":"1","categoryName":"父亲","state":"1"},{"ID":"2","categoryName":"母亲","state":"1"},{"ID":"3","categoryName":"配偶","state":"1"},{"ID":"4","categoryName":"孩子","state":"1"},{"ID":"5","categoryName":"其他","state":"1"}]      */     private int ret;     private String msg;     private List<DatasBean> datas;     public int getRet() {         return ret;     }     public void setRet(int ret) {         this.ret = ret;     }     public String getMsg() {         return msg;     }     public void setMsg(String msg) {         this.msg = msg;     }     public List<DatasBean> getDatas() {         return datas;     }     public void setDatas(List<DatasBean> datas) {         this.datas = datas;     }     public static class DatasBean {         /**          * ID : 0          * categoryName : 本人          * state : 1          */         private String ID;         private String categoryName;         private String state;         public String getID() {             return ID;         }         public void setID(String ID) {             this.ID = ID;         }         public String getCategoryName() {             return categoryName;         }         public void setCategoryName(String categoryName) {             this.categoryName = categoryName;         }         public String getState() {             return state;         }         public void setState(String state) {             this.state = state;         }     } }

2.popupwindow  

public class CommonPopWindow {     private static PopupWindow mPopupWindow;     private static Builder mBuilder;     private static View mContentView;     private static Window mWindow;     public interface ViewClickListener {         void getChildView(PopupWindow mPopupWindow, View view, int mLayoutResId);     }     private CommonPopWindow() {         mBuilder = new Builder();     }     public static Builder newBuilder() {         if (mBuilder == null) {             mBuilder = new Builder();         }         return mBuilder;     }     /**      * 获取PopupWindow宽度      *      * @return      */     public int getWidth() {         if (mPopupWindow != null) {             return mContentView.getMeasuredWidth();         }         return 0;     }     /**      * 获取PopupWindow高度      *      * @return      */     public int getHeight() {         if (mPopupWindow != null) {             return mContentView.getMeasuredHeight();         }         return 0;     }     /**      * 显示在控件的下方      */     public CommonPopWindow showDownPop(View parent) {         if (parent.getVisibility() == View.GONE) {             mPopupWindow.showAtLocation(parent, Gravity.NO_GRAVITY, 0, 0);         } else {             int[] location = new int[2];             parent.getLocationOnScreen(location);             if (mPopupWindow != null) {                 mPopupWindow.showAtLocation(parent, Gravity.NO_GRAVITY, location[0], location[1] + parent.getHeight());             }         }         return this;     }     /**      * 显示在控件的上方      */     public CommonPopWindow showAsUp(View view) {         if (view.getVisibility() == View.GONE) {             mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, 0);         } else {             int[] location = new int[2];             view.getLocationOnScreen(location);             if (mPopupWindow != null) {                 mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY, location[0], location[1] - view.getHeight());                 //方式二 //                mPopupWindow.showAsDropDown(view, 0, -(getHeight() + view.getMeasuredHeight()));             }         }         return this;     }     /**      * 显示在控件的左边      */     public CommonPopWindow showAsLeft(View view) {         if (view.getVisibility() == View.GONE) {             mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, 0);         } else {             int[] location = new int[2];             view.getLocationOnScreen(location);             if (mPopupWindow != null) {                 mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY, location[0] - getWidth(), location[1]);             }         }         return this;     }     /**      * 显示在控件右边      */     public CommonPopWindow showAsRight(View view) {         if (view.getVisibility() == View.GONE) {             mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, 0);         } else {             int[] location = new int[2];             view.getLocationOnScreen(location);             if (mPopupWindow != null) {                 mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY, location[0] + view.getWidth(), location[1]);             }         }         return this;     }     /**      * 显示控件下方      *      * @param view      * @return      */     public CommonPopWindow showAsDown(View view) {         if (mPopupWindow != null) {             mPopupWindow.showAsDropDown(view);         }         return this;     }     /**      * 全屏弹出      */     public CommonPopWindow showAsBottom(View view) {         if (view.getVisibility() == View.GONE) {             mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, 0);         } else {             int[] location = new int[2];             view.getLocationOnScreen(location);             if (mPopupWindow != null) {                 mPopupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);             }         }         return this;     }     public CommonPopWindow showAtLocation(View anchor, int gravity, int x, int y) {         if (mPopupWindow != null) {             mPopupWindow.showAtLocation(anchor, gravity, x, y);         }         return this;     }     /**      * 取消      */     public static void dismiss() {         if (mWindow != null) {             WindowManager.LayoutParams params = mWindow.getAttributes();             params.alpha = 1.0f;             mWindow.setAttributes(params);         }         if (mPopupWindow != null && mPopupWindow.isShowing())             mPopupWindow.dismiss();     }     /*      * ---------------------Builder-------------------------      */     public static class Builder implements PopupWindow.OnDismissListener {         private Context mContext;         private int mLayoutResId;//布局ID         private int mWidth, mHeight;//弹窗宽高         private int mAnimationStyle;//动画样式         private ViewClickListener mListener;//子View监听回调         private Drawable mDrawable;//背景Drawable         private boolean mTouchable = true;//是否相应touch事件         private boolean mFocusable = true;//是否获取焦点         private boolean mOutsideTouchable = true;//设置外部是否点击         private boolean mBackgroundDarkEnable = false;//是否背景窗体变暗         private float mDarkAlpha = 1.0f;//透明值         public CommonPopWindow build(Context context) {             this.mContext = context;             CommonPopWindow popWindow = new CommonPopWindow();             apply();             if (mListener != null && mLayoutResId != 0) {                 mListener.getChildView(mPopupWindow, mContentView, mLayoutResId);             }             return popWindow;         }         private void apply() {             if (mLayoutResId != 0) {                 mContentView = LayoutInflater.from(mContext).inflate(mLayoutResId, null);             }             if (mWidth != 0 && mHeight != 0) {                 mPopupWindow = new PopupWindow(mContentView, mWidth, mHeight);             } else {                 mPopupWindow = new PopupWindow(mContentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);             }             mPopupWindow.setTouchable(mTouchable);             mPopupWindow.setFocusable(mFocusable);             mPopupWindow.setOutsideTouchable(mOutsideTouchable);             if (mDrawable != null) {                 mPopupWindow.setBackgroundDrawable(mDrawable);             } else {                 mPopupWindow.setBackgroundDrawable(new ColorDrawable());             }             if (mAnimationStyle != -1) {                 mPopupWindow.setAnimationStyle(mAnimationStyle);             }             if (mWidth == 0 || mHeight == 0) {                 measureWidthAndHeight(mContentView);                 //如果没有设置高度的情况下,设置宽高并赋值                 mWidth = mPopupWindow.getContentView().getMeasuredWidth();                 mHeight = mPopupWindow.getContentView().getMeasuredHeight();             }             Activity activity = (Activity) mContext;             if (activity != null && mBackgroundDarkEnable) {                 float alpha = (mDarkAlpha >= 0f || mDarkAlpha <= 1f) ? mDarkAlpha : 0.7f;                 mWindow = activity.getWindow();                 WindowManager.LayoutParams params = mWindow.getAttributes();                 params.alpha = alpha;                 mWindow.setAttributes(params);             }             mPopupWindow.setOnDismissListener(this);             mPopupWindow.update();         }         @Override         public void onDismiss() {             dismiss();         }         /**          * 测量View的宽高          *          * @param mContentView          */         private void measureWidthAndHeight(View mContentView) {             int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);             int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);             mContentView.measure(widthMeasureSpec, heightMeasureSpec);         }         /**          * 设置布局ID          *          * @param layoutResId          * @return          */         public Builder setView(@LayoutRes int layoutResId) {             mContentView = null;             this.mLayoutResId = layoutResId;             return this;         }         /**          * 设置宽高          *          * @param width          * @param height          * @return          */         public Builder setSize(int width, int height) {             mWidth = width;             mHeight = height;             return this;         }         /**          * 设置背景          *          * @param drawable          * @return          */         public Builder setBackgroundDrawable(Drawable drawable) {             mDrawable = drawable;             return this;         }         /**          * 设置背景是否变暗          *          * @param darkEnable          * @return          */         public Builder setBackgroundDarkEnable(boolean darkEnable) {             mBackgroundDarkEnable = darkEnable;             return this;         }         /**          * 设置背景透明度          *          * @param dackAlpha          * @return          */         public Builder setBackgroundAlpha(@FloatRange(from = 0.0, to = 1.0) float dackAlpha) {             mDarkAlpha = dackAlpha;             return this;         }         /**          * 是否点击Outside消失          *          * @param touchable          * @return          */         public Builder setOutsideTouchable(boolean touchable) {             mOutsideTouchable = touchable;             return this;         }         /**          * 是否设置Touch事件          *          * @param touchable          * @return          */         public Builder setTouchable(boolean touchable) {             mTouchable = touchable;             return this;         }         /**          * 设置动画          *          * @param animationStyle          * @return          */         public Builder setAnimationStyle(@StyleRes int animationStyle) {             mAnimationStyle = animationStyle;             return this;         }         /**          * 是否设置获取焦点          *          * @param focusable          * @return          */         public Builder setFocusable(boolean focusable) {             mFocusable = focusable;             return this;         }         /**          * 设置子View点击事件回调          *          * @param listener          * @return          */         public Builder setViewOnClickListener(ViewClickListener listener) {             this.mListener = listener;             return this;         }     } }

3.pop_picker_selector_bottom.xml popupwindow布局

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="wrap_content"     tools:context=".MainActivity"     android:layout_alignParentBottom="true"     android:background="#fff"     android:orientation="vertical"     android:padding="1dp">     <TextView         android:id="@+id/img_guanbi"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_alignParentRight="true"         android:layout_marginTop="20dp"         android:layout_marginRight="15dp"         android:text="完成"         android:textColor="#d8b691"         android:textSize="16sp" />     <TextView         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_centerHorizontal="true"         android:layout_marginTop="20dp"         android:text="请选择"         android:textColor="#333"         android:textSize="16sp" />     <com.****.****.PickerScrollView         android:id="@+id/address"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_below="@id/img_guanbi"         android:layout_marginTop="10dp" /> </RelativeLayout>

4.PickerScrollView滚动控件

public class PickerScrollView extends View {     public static final String TAG = "PickerScrollView:";     /**      * text之间间距和minTextSize之比      */     public static final float MARGIN_ALPHA = 2.8f;     /**      * 自动回滚到中间的速度      */     public static final float SPEED = 2;     private List<SelectBean.DatasBean> mDataList;     /**      * 选中的位置,这个位置是mDataList的中心位置,一直不变      */     private int mCurrentSelected;     private Paint mPaint;     private float mMaxTextSize = 20;     private float mMinTextSize = 10;     private float mMaxTextAlpha = 255;     private float mMinTextAlpha = 120;     private int mColorText = 0x333333;     private int mViewHeight;     private int mViewWidth;     private float mLastDownY;     /**      * 滑动的距离      */     private float mMoveLen = 0;     private boolean isInit = false;     private onSelectListener mSelectListener;     private Timer timer;     private MyTimerTask mTask;     Handler updateHandler = new Handler() {         @Override         public void handleMessage(Message msg) {             if (Math.abs(mMoveLen) < SPEED) {                 mMoveLen = 0;                 if (mTask != null) {                     mTask.cancel();                     mTask = null;                     performSelect();                 }             } else                 // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚                 mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;             invalidate();         }     };     public PickerScrollView(Context context) {         super(context);         init();     }     public PickerScrollView(Context context, AttributeSet attrs) {         super(context, attrs);         init();     }     public void setOnSelectListener(onSelectListener listener) {         mSelectListener = listener;     }     private void performSelect() {         if (mSelectListener != null)             mSelectListener.onSelect(mDataList.get(mCurrentSelected));     }     public void setData(List<SelectBean.DatasBean> datas) {         mDataList = datas;         mCurrentSelected = datas.size() / 2;         invalidate();     }     /**      * 选择选中的item的index      *      * @param selected      */     public void setSelected(int selected) {         mCurrentSelected = selected;         int distance = mDataList.size() / 2 - mCurrentSelected;         if (distance < 0)             for (int i = 0; i < -distance; i++) {                 moveHeadToTail();                 mCurrentSelected--;             }         else if (distance > 0)             for (int i = 0; i < distance; i++) {                 moveTailToHead();                 mCurrentSelected++;             }         invalidate();     }     /**      * 选择选中的内容      *      * @param mSelectItem      */     public void setSelected(String mSelectItem) {         for (int i = 0; i < mDataList.size(); i++)             if (mDataList.get(i).equals(mSelectItem)) {                 setSelected(i);                 break;             }     }     private void moveHeadToTail() {         SelectBean.DatasBean datasBean = mDataList.get(0);         mDataList.remove(0);         mDataList.add(datasBean);     }     private void moveTailToHead() {         SelectBean.DatasBean datasBean = mDataList.get(mDataList.size() - 1);         mDataList.remove(mDataList.size() - 1);         mDataList.add(0, datasBean);     }     @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         super.onMeasure(widthMeasureSpec, heightMeasureSpec);         mViewHeight = getMeasuredHeight();         mViewWidth = getMeasuredWidth();         // 按照View的高度计算字体大小         mMaxTextSize = mViewHeight / 8.0f;         mMinTextSize = mMaxTextSize / 2f;         isInit = true;         invalidate();     }     private void init() {         timer = new Timer();         mDataList = new ArrayList<>();         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);         mPaint.setStyle(Paint.Style.FILL);         mPaint.setTextAlign(Paint.Align.CENTER);         mPaint.setColor(mColorText);     }     @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);         // 根据index绘制view         if (isInit)             drawData(canvas);     }     private void drawData(Canvas canvas) {         // 先绘制选中的text再往上往下绘制其余的text         float scale = parabola(mViewHeight / 4.0f, mMoveLen);         float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;         mPaint.setTextSize(size);         mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));         // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标         float x = (float) (mViewWidth / 2.0);         float y = (float) (mViewHeight / 2.0 + mMoveLen);         Paint.FontMetricsInt fmi = mPaint.getFontMetricsInt();         float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));         int indexs = mCurrentSelected;         String textData = mDataList.get(indexs).getCategoryName();         canvas.drawText(textData, x, baseline, mPaint);         // 绘制上方data         for (int i = 1; (mCurrentSelected - i) >= 0; i++) {             drawOtherText(canvas, i, -1);         }         // 绘制下方data         for (int i = 1; (mCurrentSelected + i) < mDataList.size(); i++) {             drawOtherText(canvas, i, 1);         }     }     /**      * @param canvas      * @param position 距离mCurrentSelected的差值      * @param type     1表示向下绘制,-1表示向上绘制      */     private void drawOtherText(Canvas canvas, int position, int type) {         float d = (float) (MARGIN_ALPHA * mMinTextSize * position + type                 * mMoveLen);         float scale = parabola(mViewHeight / 4.0f, d);         float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;         mPaint.setTextSize(size);         mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));         float y = (float) (mViewHeight / 2.0 + type * d);         Paint.FontMetricsInt fmi = mPaint.getFontMetricsInt();         float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));         int indexs = mCurrentSelected + type * position;         String textData = mDataList.get(indexs).getCategoryName();         canvas.drawText(textData, (float) (mViewWidth / 2.0), baseline, mPaint);     }     /**      * 抛物线      *      * @param zero 零点坐标      * @param x    偏移量      * @return scale      */     private float parabola(float zero, float x) {         float f = (float) (1 - Math.pow(x / zero, 2));         return f < 0 ? 0 : f;     }     @Override     public boolean onTouchEvent(MotionEvent event) {         switch (event.getActionMasked()) {             case MotionEvent.ACTION_DOWN:                 doDown(event);                 break;             case MotionEvent.ACTION_MOVE:                 doMove(event);                 break;             case MotionEvent.ACTION_UP:                 doUp(event);                 break;         }         return true;     }     private void doDown(MotionEvent event) {         if (mTask != null) {             mTask.cancel();             mTask = null;         }         mLastDownY = event.getY();     }     private void doMove(MotionEvent event) {         mMoveLen += (event.getY() - mLastDownY);         if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2) {             // 往下滑超过离开距离             moveTailToHead();             mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;         } else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2) {             // 往上滑超过离开距离             moveHeadToTail();             mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;         }         mLastDownY = event.getY();         invalidate();     }     private void doUp(MotionEvent event) {         // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置         if (Math.abs(mMoveLen) < 0.0001) {             mMoveLen = 0;             return;         }         if (mTask != null) {             mTask.cancel();             mTask = null;         }         mTask = new MyTimerTask(updateHandler);         timer.schedule(mTask, 0, 10);     }     class MyTimerTask extends TimerTask {         Handler handler;         public MyTimerTask(Handler handler) {             this.handler = handler;         }         @Override         public void run() {             handler.sendMessage(handler.obtainMessage());         }     }     public interface onSelectListener {         void onSelect(SelectBean.DatasBean pickers);     } }

5.activity_main.xml布局

<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context=".MainActivity">     <TextView         android:id="@+id/textClick"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:text="Hello World!"         app:layout_constraintBottom_toBottomOf="parent"         app:layout_constraintLeft_toLeftOf="parent"         app:layout_constraintRight_toRightOf="parent"         app:layout_constraintTop_toTopOf="parent" />     <TextView         android:id="@+id/text"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:text="Hello World!"         app:layout_constraintBottom_toBottomOf="parent"         app:layout_constraintLeft_toLeftOf="parent"         app:layout_constraintRight_toRightOf="parent"         app:layout_constraintTop_toTopOf="parent"         android:layout_marginTop="50dp"/> </androidx.constraintlayout.widget.ConstraintLayout>

6.mainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener,CommonPopWindow.ViewClickListener {     private TextView click;     private TextView text;     private String categoryName;     private List<SelectBean.DatasBean> datas;     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         initView();         initData();         initListener();     }     private void initListener() {         click.setOnClickListener(this);     }     private void initData() {         //模拟请求后台返回数据         String response = "{\"ret\":0,\"msg\":\"succes,\",\"datas\":[{\"ID\":\" 0\",\"categoryName\":\"本人\",\"state\":\"1\"},{\"ID\":\"1\",\"categoryName\":\"父亲\",\"state\":\"1\"},{\"ID\":\"2\",\"categoryName\":\"母亲\",\"state\":\"1\"},{\"ID\":\"3\",\"categoryName\":\"配偶\",\"state\":\"1\"},{\"ID\":\"4\",\"categoryName\":\"其他\",\"state\":\"1\"}]}";         SelectBean selectBean = new Gson().fromJson(response, SelectBean.class);         //0请求表示成功         if (selectBean.getRet() == 0) {             //滚动选择数据集合             datas = selectBean.getDatas();         }     }     private void initView() {         click = findViewById(R.id.textClick);         text = findViewById(R.id.text);     }     @Override     public void onClick(View v) {         switch (v.getId()) {             case R.id.textClick:                 setAddressSelectorPopup(v);                 break;         }     }     /**      * 将选择器放在底部弹出框      * @param v      */     private void setAddressSelectorPopup(View v) {         int screenHeigh = getResources().getDisplayMetrics().heightPixels;         CommonPopWindow.newBuilder()                 .setView(R.layout.pop_picker_selector_bottom)                // .setAnimationStyle(R.style.AnimUp)                 .setBackgroundDrawable(new BitmapDrawable())                 .setSize(ViewGroup.LayoutParams.MATCH_PARENT, Math.round(screenHeigh * 0.3f))                 .setViewOnClickListener(this)                 .setBackgroundDarkEnable(true)                 .setBackgroundAlpha(0.7f)                 .setBackgroundDrawable(new ColorDrawable(999999))                 .build(this)                 .showAsBottom(v);     }     @Override     public void getChildView(final PopupWindow mPopupWindow, View view, int mLayoutResId) {         switch (mLayoutResId) {             case R.layout.pop_picker_selector_bottom:                 TextView imageBtn = view.findViewById(R.id.img_guanbi);                 PickerScrollView addressSelector = view.findViewById(R.id.address);                 // 设置数据,默认选择第一条                 addressSelector.setData(datas);                 addressSelector.setSelected(0);                 //滚动监听                 addressSelector.setOnSelectListener(new PickerScrollView.onSelectListener() {                     @Override                     public void onSelect(SelectBean.DatasBean pickers) {                         categoryName = pickers.getCategoryName();                     }                 });                 //完成按钮                 imageBtn.setOnClickListener(new View.OnClickListener() {                     @Override                     public void onClick(View v) {                         mPopupWindow.dismiss();                         if (categoryName==null){                             text.setText(datas.get(2).getCategoryName());                             Toast.makeText(MainActivity.this, "默认第一条", Toast.LENGTH_SHORT).show();                         }else {                             text.setText(categoryName);                             Toast.makeText(MainActivity.this, "滚动选择", Toast.LENGTH_SHORT).show();                         }                     }                 });                 break;         }     } }



选择 方法 Android

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章