到处偷来的,知道出处的请告知一下,谢谢
1、需要多行的radioGroup
2、tablayout跟viewpager组合的adapter
3、底部导航栏 加图标的
4、图形验证码生成
5、短信倒计时
6、正则工具类 验证邮箱、手机号、电话号码、身份证号码、数字等方法
- 需要多行的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>
- 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)
- 底部导航栏 加图标的
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)
- 图形验证码生成
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
}
}
}
- 短信倒计时
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) //还原背景色
}
}
- 正则工具类 验证邮箱、手机号、电话号码、身份证号码、数字等方法
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)
}
}
- BaseActivity