我的项目常用的一些工具类

到处偷来的,知道出处的请告知一下,谢谢

1、需要多行的radioGroup
2、tablayout跟viewpager组合的adapter
3、底部导航栏 加图标的
4、图形验证码生成
5、短信倒计时
6、正则工具类 验证邮箱、手机号、电话号码、身份证号码、数字等方法

  1. 需要多行的radioGroup
public class MultiLineRadioGroup extends LinearLayout {
    // holds the checked id; the selection is empty by default
    private int mCheckedId = -1;
    // tracks children radio buttons checked state
    private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
    // when true, mOnCheckedChangeListener discards events
    private boolean mProtectFromCheckedChange = false;
    private OnCheckedChangeListener mOnCheckedChangeListener;
    private PassThroughHierarchyChangeListener mPassThroughListener;

    /**
     * {@inheritDoc}
     */
    public MultiLineRadioGroup(Context context) {
        super(context);
        setOrientation(VERTICAL);
        init();
    }

    /**
     * {@inheritDoc}
     */
    public MultiLineRadioGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        mChildOnCheckedChangeListener = new CheckedStateTracker();
        mPassThroughListener = new PassThroughHierarchyChangeListener();
        super.setOnHierarchyChangeListener(mPassThroughListener);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
        // the user listener is delegated to our pass-through listener
        mPassThroughListener.mOnHierarchyChangeListener = listener;
    }

    /**
     * set the default checked radio button, without notification the listeners
     */
    public void setCheckWithoutNotif(int id) {
        if (id != -1 && (id == mCheckedId)) {
            return;
        }

        mProtectFromCheckedChange = true;
        if (mCheckedId != -1) {
            setCheckedStateForView(mCheckedId, false);
        }

        if (id != -1) {
            setCheckedStateForView(id, true);
        }

        mCheckedId = id;
        mProtectFromCheckedChange = false;
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        List<RadioButton> btns = getAllRadioButton(child);
        if (btns != null && btns.size() > 0) {
            for (RadioButton button : btns) {
                if (button.isChecked()) {
                    mProtectFromCheckedChange = true;
                    if (mCheckedId != -1) {
                        setCheckedStateForView(mCheckedId, false);
                    }
                    mProtectFromCheckedChange = false;
                    setCheckedId(button.getId());
                }
            }
        }
        super.addView(child, index, params);
    }

    /**
     * get all radio buttons which are in the view
     *
     * @param child
     */
    private List<RadioButton> getAllRadioButton(View child) {
        List<RadioButton> btns = new ArrayList<RadioButton>();
        if (child instanceof RadioButton) {
            btns.add((RadioButton) child);
        } else if (child instanceof ViewGroup) {
            int counts = ((ViewGroup) child).getChildCount();
            for (int i = 0; i < counts; i++) {
                btns.addAll(getAllRadioButton(((ViewGroup) child).getChildAt(i)));
            }
        }
        return btns;
    }

    /**
     * <p>Sets the selection to the radio button whose identifier is passed in
     * parameter. Using -1 as the selection identifier clears the selection;
     * such an operation is equivalent to invoking {@link #clearCheck()}.</p>
     *
     * @param id the unique id of the radio button to select in this group
     * @see #getCheckedRadioButtonId()
     * @see #clearCheck()
     */
    public void check(int id) {
        // don't even bother
        if (id != -1 && (id == mCheckedId)) {
            return;
        }

        if (mCheckedId != -1) {
            setCheckedStateForView(mCheckedId, false);
        }

        if (id != -1) {
            setCheckedStateForView(id, true);
        }

        setCheckedId(id);
    }

    private void setCheckedId(int id) {
        mCheckedId = id;
        if (mOnCheckedChangeListener != null) {
            mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
        }
    }

    private void setCheckedStateForView(int viewId, boolean checked) {
        View checkedView = findViewById(viewId);
        if (checkedView != null && checkedView instanceof RadioButton) {
            ((RadioButton) checkedView).setChecked(checked);
        }
    }

    /**
     * <p>Returns the identifier of the selected radio button in this group.
     * Upon empty selection, the returned value is -1.</p>
     *
     * @return the unique id of the selected radio button in this group
     * @attr ref android.R.styleable#MyRadioGroup_checkedButton
     * @see #check(int)
     * @see #clearCheck()
     */
    public int getCheckedRadioButtonId() {
        return mCheckedId;
    }

    /**
     * <p>Clears the selection. When the selection is cleared, no radio button
     * in this group is selected and {@link #getCheckedRadioButtonId()} returns
     * null.</p>
     *
     * @see #check(int)
     * @see #getCheckedRadioButtonId()
     */
    public void clearCheck() {
        check(-1);
    }

    /**
     * <p>Register a callback to be invoked when the checked radio button
     * changes in this group.</p>
     *
     * @param listener the callback to call on checked state change
     */
    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
        mOnCheckedChangeListener = listener;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MultiLineRadioGroup.LayoutParams(getContext(), attrs);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof MultiLineRadioGroup.LayoutParams;
    }

    @Override
    protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
        event.setClassName(MultiLineRadioGroup.class.getName());
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
        info.setClassName(MultiLineRadioGroup.class.getName());
    }

    /**
     * <p>This set of layout parameters defaults the width and the height of
     * the children to {@link #WRAP_CONTENT} when they are not specified in the
     * XML file. Otherwise, this class ussed the value read from the XML file.</p>
     * <p/>
     * <p>See
     * for a list of all child view attributes that this class supports.</p>
     */
    public static class LayoutParams extends LinearLayout.LayoutParams {
        /**
         * {@inheritDoc}
         */
        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        /**
         * {@inheritDoc}
         */
        public LayoutParams(int w, int h) {
            super(w, h);
        }

        /**
         * {@inheritDoc}
         */
        public LayoutParams(int w, int h, float initWeight) {
            super(w, h, initWeight);
        }

        /**
         * {@inheritDoc}
         */
        public LayoutParams(ViewGroup.LayoutParams p) {
            super(p);
        }

        /**
         * {@inheritDoc}
         */
        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        /**
         * <p>Fixes the child's width to
         * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and the child's
         * height to  {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
         * when not specified in the XML file.</p>
         *
         * @param a          the styled attributes set
         * @param widthAttr  the width attribute to fetch
         * @param heightAttr the height attribute to fetch
         */
        @Override
        protected void setBaseAttributes(TypedArray a,
                                         int widthAttr, int heightAttr) {

            if (a.hasValue(widthAttr)) {
                width = a.getLayoutDimension(widthAttr, "layout_width");
            } else {
                width = WRAP_CONTENT;
            }

            if (a.hasValue(heightAttr)) {
                height = a.getLayoutDimension(heightAttr, "layout_height");
            } else {
                height = WRAP_CONTENT;
            }
        }
    }

    /**
     * <p>Interface definition for a callback to be invoked when the checked
     * radio button changed in this group.</p>
     */
    public interface OnCheckedChangeListener {
        /**
         * <p>Called when the checked radio button has changed. When the
         * selection is cleared, checkedId is -1.</p>
         *
         * @param group     the group in which the checked radio button has changed
         * @param checkedId the unique identifier of the newly checked radio button
         */
        public void onCheckedChanged(MultiLineRadioGroup group, int checkedId);
    }

    private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            // prevents from infinite recursion
            if (mProtectFromCheckedChange) {
                return;
            }

            mProtectFromCheckedChange = true;
            if (mCheckedId != -1) {
                setCheckedStateForView(mCheckedId, false);
            }
            mProtectFromCheckedChange = false;

            int id = buttonView.getId();
            setCheckedId(id);
        }
    }

    /**
     * <p>A pass-through listener acts upon the events and dispatches them
     * to another listener. This allows the table layout to set its own internal
     * hierarchy change listener without preventing the user to setup his.</p>
     */
    private class PassThroughHierarchyChangeListener implements
            ViewGroup.OnHierarchyChangeListener {
        private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;

        /**
         * {@inheritDoc}
         */
        @SuppressLint("NewApi")
        public void onChildViewAdded(View parent, View child) {
            if (parent == MultiLineRadioGroup.this) {
                List<RadioButton> btns = getAllRadioButton(child);
                if (btns != null && btns.size() > 0) {
                    for (RadioButton btn : btns) {
                        int id = btn.getId();
                        // generates an id if it's missing
                        if (id == View.NO_ID && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                            id = View.generateViewId();
                            btn.setId(id);
                        }
                        btn.setOnCheckedChangeListener(
                                mChildOnCheckedChangeListener);
                    }
                }
            }

            if (mOnHierarchyChangeListener != null) {
                mOnHierarchyChangeListener.onChildViewAdded(parent, child);
            }
        }

        /**
         * {@inheritDoc}
         */
        public void onChildViewRemoved(View parent, View child) {
            if (parent == MultiLineRadioGroup.this) {
                List<RadioButton> btns = getAllRadioButton(child);
                if (btns != null && btns.size() > 0) {
                    for (RadioButton btn : btns) {
                        btn.setOnCheckedChangeListener(null);
                    }
                }
            }

            if (mOnHierarchyChangeListener != null) {
                mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
            }
        }
    }
}

xml代码:

<com.sl.xdll.utils.MultiLineRadioGroup
        android:id="@+id/mlrg_meal_time_fpv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <RadioButton
                android:id="@+id/rb_breakfast_fpv"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="早餐"
                android:button="@null"
                android:padding="6dp"
                android:layout_margin="12dp"
                android:gravity="center"
                android:background="@drawable/shape_radio_frame_bg"
                style="@style/TextNormal"/>
            <RadioButton
                android:id="@+id/rb_lunch_fpv"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="午餐"
                android:button="@null"
                android:padding="6dp"
                android:layout_margin="12dp"
                android:gravity="center"
                android:background="@drawable/shape_radio_frame_bg"
                style="@style/TextNormal"/>
            <RadioButton
                android:layout_width="0dp"
                android:layout_weight="1"
                android:button="@null"
                android:layout_height="wrap_content"
                android:text="下午茶"
                android:padding="6dp"
                android:layout_margin="12dp"
                android:gravity="center"
                android:background="@drawable/shape_radio_frame_bg"
                style="@style/TextNormal"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <RadioButton
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="晚餐"
                android:button="@null"
                android:padding="6dp"
                android:layout_marginStart="12dp"
                android:layout_marginEnd="12dp"
                android:gravity="center"
                android:background="@drawable/shape_radio_frame_bg"
                style="@style/TextNormal"/>
            <RadioButton
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_marginStart="12dp"
                android:layout_marginEnd="12dp"
                android:layout_height="wrap_content"
                android:text="夜宵"
                android:button="@null"
                android:padding="6dp"
                android:gravity="center"
                android:background="@drawable/shape_radio_frame_bg"
                style="@style/TextNormal"/>
            <TextView
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:padding="6dp"
                android:layout_marginStart="12dp"
                android:layout_marginEnd="12dp"
                android:gravity="center"
                style="@style/TextNormal"/>
        </LinearLayout>
    </com.sl.xdll.utils.MultiLineRadioGroup>
  1. tablayout跟viewpager组合的adapter
class TitleFragmentPagerAdapter : FragmentPagerAdapter {
    /**
     * The m fragment list.
     */
    private var mFragmentList: List<Fragment>? = null

    private lateinit var titles: Array<String>

    /**
     * 描述:获取数量.
     *
     * @return the count
     * @see android.support.v4.view.PagerAdapter.getCount
     */
     override fun getCount(): Int {
        return mFragmentList!!.size
    }


    /**
     * Instantiates a new ab fragment pager adapter.
     *
     * @param mFragmentManager the m fragment manager
     * @param fragmentList     the fragment list
     */
    constructor(mFragmentManager: FragmentManager,
                fragmentList: ArrayList<Fragment>) : super(mFragmentManager) {
        mFragmentList = fragmentList
    }

    /**
     * titles是给TabLayout设置title用的
     *
     * @param mFragmentManager
     * @param fragmentList
     * @param titles
     */
    constructor(mFragmentManager: FragmentManager,
                fragmentList: List<Fragment>, titles: Array<String>) : super(mFragmentManager) {
        mFragmentList = fragmentList
        this.titles = titles
    }

    /**
     * 描述:获取索引位置的Fragment.
     *
     * @param position the position
     * @return the item
     * @see android.support.v4.app.FragmentPagerAdapter.getItem
     */
    override fun getItem(position: Int): Fragment? {

        var fragment: Fragment? = null
        fragment = if (position < mFragmentList!!.size) {
            mFragmentList!![position]
        } else {
            mFragmentList!![0]
        }
        return fragment
    }

    override fun getPageTitle(position: Int): CharSequence? {
        return if (titles.isNotEmpty()) titles[position] else null
    }
}

xml布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tl_nearby_ans"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:tabIndicatorColor="@color/textYellow"
        app:tabMode="fixed"
        app:tabSelectedTextColor="@color/textYellow"
        app:tabTextColor="#000000">

    </android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp_nearby_ans"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v4.view.ViewPager>

</LinearLayout>

用法:

 val fragments = ArrayList<Fragment>()
        fragments.add(XSearchAllShopsFragment())
        fragments.add(XResidentShopFragment())
        fragments.add(XBusinessShopFragment())

        val adapter = TitleFragmentPagerAdapter(supportFragmentManager, fragments, arrayOf("全部店铺", "居民店铺", "商业店铺"))
        vp_nearby_ans.adapter = adapter
        vp_nearby_ans.offscreenPageLimit=3
        tl_nearby_ans.setupWithViewPager(vp_nearby_ans)
  1. 底部导航栏 加图标的
class FragmentSwitchTool(private var fragmentManager: FragmentManager, private var containerId: Int) : View.OnClickListener {

    private var currentFragment: Fragment? = null
    private lateinit var currentSelectedView: Array<View>
    private var clickableViews: ArrayList<View> = ArrayList()
    private var selectedViews: MutableList<Array<View>> = ArrayList()
    private var fragments: ArrayList<Class<out Fragment>> = ArrayList()
//    private var bundles: ArrayList<Bundle> = ArrayList()
//    private val showAnimator: Boolean = false


    fun setClickableViews(vararg clickableViews: View) {
        for (view in clickableViews) {
            this.clickableViews.add(view)
            view.setOnClickListener(this)
        }
    }

//    fun setBundles(vararg bundles: Bundle) {
//        for (bundle in bundles) {
//            this.bundles.add(bundle)
//        }
//    }

    fun addSelectedViews(views: Array<View>): FragmentSwitchTool {
        selectedViews.add(views)
        return this
    }

    fun setFragments(vararg fragments: Class<out Fragment>) {
        for (fragment in fragments) {
            this.fragments.add(fragment)
        }
    }

    fun changeTag(v: View) {
        val fragmentTransaction = fragmentManager.beginTransaction()
        var fragment: Fragment? = fragmentManager.findFragmentByTag(v.id.toString())
        for (i in clickableViews.indices) {
            if (v.id == clickableViews[i].id) {

//                //过渡动画
//                if (showAnimator) {
//                    val exitIndex = selectedViews.indexOf(currentSelectedView)
//                    if (i > exitIndex) {
//                                                fragmentTransaction.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out);
//                    } else if (i < exitIndex) {
//                                                fragmentTransaction.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_right_out);
//                    }
//                }
                //过渡动画,这个类在这里处理的了Null的状态,所以不需要保存,但是我想说的处理方式和这个不一样
                if (fragment == null) {
                    if (currentFragment != null) {
                        fragmentTransaction.hide(currentFragment)
                        for (view in currentSelectedView) {
                            view.isSelected = false
                        }
                    }
                        fragment = fragments[i].newInstance()

//                        if (bundles != null && bundles[i] != null) {
//                            fragment.arguments = bundles[i]
//                        }


                    fragmentTransaction.add(containerId, fragment, clickableViews[i].id.toString())
                } else if (fragment === currentFragment) {
                } else {
                    fragmentTransaction.hide(currentFragment)
                    for (view in currentSelectedView) {
                        view.isSelected = false
                    }
                    fragmentTransaction.show(fragment)
                }

                fragmentTransaction.commitAllowingStateLoss()
                currentFragment = fragment
                for (view in selectedViews[i]) {
                    view.isSelected = true
                }
                currentSelectedView = selectedViews[i]
                break
            }
        }
    }


    override fun onClick(p0: View?) {
        if (p0 == null) {
            return
        }
        changeTag(p0)
    }

}

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <FrameLayout
        android:id="@+id/framelayout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

    </FrameLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#999999" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginBottom="6dp"
        android:orientation="horizontal">

        <LinearLayout
            android:id="@+id/one_ll"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/one_iv"
                android:layout_width="23dp"
                android:layout_height="23dp"
                android:layout_marginTop="6dp"
                android:padding="2dp"
                android:src="@drawable/bg_main_home_icon_selected" />

            <TextView
                android:id="@+id/one_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:textColor="@drawable/bg_main_item_text_selected"
                android:text="首页"/>

        </LinearLayout>

        <LinearLayout
            android:id="@+id/two_ll"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/two_iv"
                android:layout_width="23dp"
                android:layout_height="23dp"
                android:layout_marginTop="6dp"
                android:src="@drawable/bg_main_sort_icon"/>

            <TextView
                android:id="@+id/two_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:textColor="@drawable/bg_main_item_text_selected"
                android:text="分类"/>

        </LinearLayout>

        <LinearLayout
            android:id="@+id/three_ll"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/three_iv"
                android:layout_width="23dp"
                android:layout_height="23dp"
                android:layout_marginTop="6dp"
                android:src="@drawable/bg_main_car_icon_selected" />

            <TextView
                android:id="@+id/three_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:textColor="@drawable/bg_main_item_text_selected"
                android:text="购物车" />

        </LinearLayout>

        <LinearLayout
            android:id="@+id/four_ll"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/four_iv"
                android:layout_width="26dp"
                android:layout_height="26dp"
                android:layout_marginTop="6dp"
                android:src="@drawable/bg_main_mine_icon_selected" />

            <TextView
                android:id="@+id/four_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@drawable/bg_main_item_text_selected"
                android:text="我的" />

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

用法:

 fragmentSwitchTool = FragmentSwitchTool(supportFragmentManager, R.id.framelayout)
        fragmentSwitchTool.setClickableViews(one_ll,two_ll,three_ll,four_ll)
        fragmentSwitchTool.addSelectedViews(arrayOf<View>(one_tv, one_iv))
                .addSelectedViews(arrayOf<View>(two_tv, two_iv))
                .addSelectedViews(arrayOf<View>(three_tv, three_iv))
                .addSelectedViews(arrayOf<View>(four_tv, four_iv))
        fragmentSwitchTool.setFragments(HomeFragment::class.java, SortFragment::class.java, ShopCarFragment::class.java, MineFragment::class.java)
        fragmentSwitchTool.changeTag(one_ll)
  1. 图形验证码生成
class CodeUtils {
    private var mPaddingLeft: Int = 0
    private var mPaddingTop: Int = 0
    private val mBuilder = StringBuilder()
    private val mRandom = Random()

    /**
     * 得到图片中的验证码字符串

     * @return
     */
    var code: String? = null
        private set

    //生成验证码图片  返回类型为bitmap 直接用imageview.setbitmap()即可
    fun createBitmap(code1: String): Bitmap {
        mPaddingLeft = 0 //每次生成验证码图片时初始化
        mPaddingTop = 0

        val bitmap = Bitmap.createBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)

        //        code = createCode(CHARS);
        code = code1

        canvas.drawColor(Color.rgb(DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_COLOR))
        val paint = Paint()
        paint.textSize = DEFAULT_FONT_SIZE.toFloat()

        for (i in 0..code!!.length - 1) {
            randomTextStyle(paint)
            randomPadding()
            canvas.drawText(code!![i] + "", mPaddingLeft.toFloat(), mPaddingTop.toFloat(), paint)
        }

        //干扰线
        for (i in 0..DEFAULT_LINE_NUMBER - 1) {
            drawLine(canvas, paint)
        }

        canvas.save(Canvas.ALL_SAVE_FLAG)//保存
        canvas.restore()
        return bitmap
    }

    //生成验证码
    fun createCode(CHARS: CharArray): String {
        mBuilder.delete(0, mBuilder.length) //使用之前首先清空内容

        for (i in 0..DEFAULT_CODE_LENGTH - 1) {
            mBuilder.append(CHARS[i])
            //            mBuilder.append(CHARS[mRandom.nextInt(CHARS.length)]);
        }

        return mBuilder.toString()
    }

    //生成干扰线
    private fun drawLine(canvas: Canvas, paint: Paint) {
        val color = randomColor()
        val startX = mRandom.nextInt(DEFAULT_WIDTH)
        val startY = mRandom.nextInt(DEFAULT_HEIGHT)
        val stopX = mRandom.nextInt(DEFAULT_WIDTH)
        val stopY = mRandom.nextInt(DEFAULT_HEIGHT)
        paint.strokeWidth = 1f
        paint.color = color
        canvas.drawLine(startX.toFloat(), startY.toFloat(), stopX.toFloat(), stopY.toFloat(), paint)
    }

    //随机颜色
    private fun randomColor(): Int {
        mBuilder.delete(0, mBuilder.length) //使用之前首先清空内容

        var haxString: String
        for (i in 0..2) {
            haxString = Integer.toHexString(mRandom.nextInt(0xFF))
            if (haxString.length == 1) {
                haxString = "0" + haxString
            }

            mBuilder.append(haxString)
        }

        return Color.parseColor("#" + mBuilder.toString())
    }

    //随机文本样式
    private fun randomTextStyle(paint: Paint) {
        val color = randomColor()
        paint.color = color
        paint.isFakeBoldText = mRandom.nextBoolean()  //true为粗体,false为非粗体
        var skewX = (mRandom.nextInt(11) / 10).toFloat()
        skewX = if (mRandom.nextBoolean()) skewX else -skewX
        paint.textSkewX = skewX //float类型参数,负数表示右斜,整数左斜
        //        paint.setUnderlineText(true); //true为下划线,false为非下划线
        //        paint.setStrikeThruText(true); //true为删除线,false为非删除线
    }

    //随机间距
    private fun randomPadding() {
        mPaddingLeft += BASE_PADDING_LEFT + mRandom.nextInt(RANGE_PADDING_LEFT)
        mPaddingTop = BASE_PADDING_TOP + mRandom.nextInt(RANGE_PADDING_TOP)
    }

    companion object {
        //    private static final char[] CHARS = {
        //            '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',
        //
        //    };

        private var mCodeUtils: CodeUtils? = null

        //Default Settings
        //    private static final int DEFAULT_CODE_LENGTH = 6;//验证码的长度  这里是6位
        private val DEFAULT_CODE_LENGTH = 4//验证码的长度  这里是4位
        private val DEFAULT_FONT_SIZE = 60//字体大小
        private val DEFAULT_LINE_NUMBER = 3//多少条干扰线
        private val BASE_PADDING_LEFT = 40 //左边距
        private val RANGE_PADDING_LEFT = 30//左边距范围值
        private val BASE_PADDING_TOP = 70//上边距
        private val RANGE_PADDING_TOP = 15//上边距范围值
        private val DEFAULT_WIDTH = 300//默认宽度.图片的总宽
        private val DEFAULT_HEIGHT = 100//默认高度.图片的总高
        private val DEFAULT_COLOR = 0xDF//默认背景颜色值

        val instance: CodeUtils
            get() {
                if (mCodeUtils == null) {
                    mCodeUtils = CodeUtils()
                }
                return mCodeUtils as CodeUtils
            }
    }
}

  1. 短信倒计时
class CountDownTimerUtils
/**
 * @param textView          The TextView
 * *
 * @param millisInFuture    The number of millis in the future from the call
 * *                          to [.start] until the countdown is done and [.onFinish]
 * *                          is called.
 * *
 * @param countDownInterval The interval along the way to receiver
 * *                          [.onTick] callbacks.
 */
(private val mTextView: TextView, millisInFuture: Long, countDownInterval: Long) : CountDownTimer(millisInFuture, countDownInterval) {

    @SuppressLint("SetTextI18n")
    override fun onTick(millisUntilFinished: Long) {
        mTextView.isClickable = false //设置不可点击
        mTextView.text = (millisUntilFinished / 1000).toString() + "秒可重新发送"  //设置倒计时时间
        mTextView.setBackgroundResource(R.drawable.bg_identify_code_press) //设置按钮为灰色,这时是不能点击的

        /**
         * 超链接 URLSpan
         * 文字背景颜色 BackgroundColorSpan
         * 文字颜色 ForegroundColorSpan
         * 字体大小 AbsoluteSizeSpan
         * 粗体、斜体 StyleSpan
         * 删除线 StrikethroughSpan
         * 下划线 UnderlineSpan
         * 图片 ImageSpan
         * http://blog.youkuaiyun.com/ah200614435/article/details/7914459
         */
        val spannableString = SpannableString(mTextView.text.toString())  //获取按钮上的文字
        val span = ForegroundColorSpan(Color.RED)
        /**
         * public void setSpan(Object what, int start, int end, int flags) {
         * 主要是start跟end,start是起始位置,无论中英文,都算一个。
         * 从0开始计算起。end是结束位置,所以处理的文字,包含开始位置,但不包含结束位置。
         */
        spannableString.setSpan(span, 0, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)//将倒计时的时间设置为红色
        mTextView.text = spannableString
    }

    override fun onFinish() {
        mTextView.text = "重新获取验证码"
        mTextView.isClickable = true//重新获得点击
        mTextView.setBackgroundResource(R.drawable.bg_identify_code_normal)  //还原背景色
    }
}

  1. 正则工具类 验证邮箱、手机号、电话号码、身份证号码、数字等方法
object RegexUtils {
    /**
     * 验证Email
     * @param email email地址,格式:zhangsan@sina.com,zhangsan@xxx.com.cn,xxx代表邮件服务商
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkEmail(email: String): Boolean {
        val regex = "\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?"
        return Pattern.matches(regex, email)
    }

    /**
     * 判断手机号码是否合理

     * @param phoneNums
     */
    fun checkMobile(phoneNums: String): Boolean {
        if (isMatchLength(phoneNums, 11) && isMobileNO(phoneNums)) {
            return true
        }
        return false
    }

    /**
     * 判断一个字符串的位数

     * @param str
     * *
     * @param length
     * *
     * @return
     */
    @SuppressLint("NewApi")
    private fun isMatchLength(str: String, length: Int): Boolean {
        if (str.isEmpty()) {
            return false
        } else {
            return str.length == length
        }
    }

    /**
     * 验证手机格式
     */
    private fun isMobileNO(mobileNums: String): Boolean {
        /*
         * 移动:134、135、136、137、138、139、150、151、157(TD)、158、159、187、188
         * 联通:130、131、132、152、155、156、185、186 电信:133、153、180、189、(1349卫通)、177
         * 总结起来就是第一位必定为1,第二位必定为3或5或8,其他位置的可以为0-9
         */
        val telRegex = "[1][3578]\\d{9}"// "[1]"代表第1位为数字1,"[358]"代表第二位可以为3、5、8中的一个,"\\d{9}"代表后面是可以是0~9的数字,有9位。
        if (TextUtils.isEmpty(mobileNums))
            return false
        else
            return mobileNums.matches(telRegex.toRegex())
    }


    /**
     * 验证整数(正整数和负整数)

     * @param digit 一位或多位0-9之间的整数
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkDigit(digit: String): Boolean {
        val regex = "-?[1-9]\\d+"
        return Pattern.matches(regex, digit)
    }

    /**
     * 验证整数和浮点数(正负整数和正负浮点数)

     * @param decimals 一位或多位0-9之间的浮点数,如:1.23,233.30
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkDecimals(decimals: String): Boolean {
        val regex = "-?[1-9]\\d+(\\.\\d+)?"
        return Pattern.matches(regex, decimals)
    }

    /**
     * 验证空白字符

     * @param blankSpace 空白字符,包括:空格、\t、\n、\r、\f、\x0B
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkBlankSpace(blankSpace: String): Boolean {
        val regex = "\\s+"
        return Pattern.matches(regex, blankSpace)
    }

    /**
     * 验证中文

     * @param chinese 中文字符
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkChinese(chinese: String): Boolean {
        val regex = "^[\u4E00-\u9FA5]+$"
        return Pattern.matches(regex, chinese)
    }

    /**
     * 验证日期(年月日)

     * @param birthday 日期,格式:1992-09-03,或1992.09.03
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkBirthday(birthday: String): Boolean {
        val regex = "[1-9]{4}([-./])\\d{1,2}\\u0001\\d{1,2}"
        return Pattern.matches(regex, birthday)
    }

    /**
     * 验证URL地址

     * @param url 格式:http://blog.youkuaiyun.com:80/xyang81/article/details/7705960? 或 http://www.youkuaiyun.com:80
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkURL(url: String): Boolean {
        val regex = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?"
        return Pattern.matches(regex, url)
    }

    /**
     * 匹配中国邮政编码

     * @param postcode 邮政编码
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkPostcode(postcode: String): Boolean {
        val regex = "[1-9]\\d{5}"
        return Pattern.matches(regex, postcode)
    }

    /**
     * 匹配IP地址(简单匹配,格式,如:192.168.1.1,127.0.0.1,没有匹配IP段的大小)

     * @param ipAddress IPv4标准地址
     * *
     * @return 验证成功返回true,验证失败返回false
     */
    fun checkIpAddress(ipAddress: String): Boolean {
        val regex = "[1-9](\\d{1,2})?\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))"
        return Pattern.matches(regex, ipAddress)
    }
}

  1. BaseActivity
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值