Commit b50acce0 authored by xuelimin's avatar xuelimin

分批1

parent 5087913e
Pipeline #1092 canceled with stages
package com.rudian.library.ui.camera
import com.yalantis.ucrop.UCrop
/**
* Created on 2018/7/12 11:27
* Created by 薛立民
* TEL 13262933389
*/
object RequestCodes {
val TAKE_PHOTO = 4
val PICK_PHOTO = 5
val CROP_PHOTO = UCrop.REQUEST_CROP
val CROP_ERROR = UCrop.RESULT_ERROR
val SCAN = 7
}
package com.rudian.library.ui.dialog
import android.app.Dialog
import android.content.Context
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.Gravity
import android.view.WindowManager
import com.rudian.library.R
import com.rudian.library.ui.recycler.MultipleRecyclerAdapter
import kotlinx.android.synthetic.main.dialog_bottom.*
/**
* Created on 2019-08-28
* Created by xuelimin
*/
class BottomDialog : Dialog {
private var listener: MultipleRecyclerAdapter.OnItemClickListener? = null
private var mAdapter: MultipleRecyclerAdapter? = null
constructor(context: Context, mAdapter: MultipleRecyclerAdapter,
listener: MultipleRecyclerAdapter.OnItemClickListener) : super(context, R.style.ShareDialog) {
this.mAdapter = mAdapter
this.listener = listener
initView()
}
constructor(context: Context, themeStyle: Int, mAdapter: MultipleRecyclerAdapter,
listener: MultipleRecyclerAdapter.OnItemClickListener) : super(context, themeStyle) {
this.mAdapter = mAdapter
this.listener = listener
initView()
}
private fun initView() {
setContentView(R.layout.dialog_bottom)
// 设置Dialog参数
window!!.attributes.width = WindowManager.LayoutParams.MATCH_PARENT
window!!.attributes.height = WindowManager.LayoutParams.WRAP_CONTENT
window!!.attributes.gravity = Gravity.BOTTOM
window!!.attributes = window!!.attributes
val layoutManager = LinearLayoutManager(context)
layoutManager.orientation = LinearLayoutManager.VERTICAL
mRvDialogContent.layoutManager = layoutManager
mAdapter!!.setOnItemListener(listener)
mRvDialogContent.adapter = mAdapter
}
}
\ No newline at end of file
package com.rudian.library.ui
import android.content.Context
import androidx.appcompat.app.AppCompatDialog
import android.view.Gravity
import com.rudian.library.R
import com.rudian.library.util.dimen.DimenUtil
import java.util.*
/**
* Created on 2019-08-20
* Created by xuelimin
*/
class HomeBozzLoader {
companion object {
private val LOADER_SIZE_SCALE = 8
private val LOADER_OFFSET_SCALE = 10
private val LOADERS = ArrayList<AppCompatDialog>()
private val DEFAULT_LOADER = LoaderStyle.BallClipRotatePulseIndicator.name
fun showLoading(context: Context, type: String) {
val dialog = AppCompatDialog(context, R.style.dialog)
val avLoadingIndicatorView = LoaderCreator().create(type, context)
dialog.setContentView(avLoadingIndicatorView)
dialog.setCancelable(false)
val deviceWidth = DimenUtil.screenWidth
val deviceHeight = DimenUtil.screenHeight
val dialogWindow = dialog.window
if (dialogWindow != null) {
val lp = dialogWindow.attributes
lp.width = deviceWidth / LOADER_SIZE_SCALE
lp.height = deviceHeight / LOADER_SIZE_SCALE
lp.height = lp.height + deviceHeight / LOADER_OFFSET_SCALE
lp.gravity = Gravity.CENTER
}
LOADERS.add(dialog)
dialog.show()
}
fun showLoading(context: Context, type: Enum<LoaderStyle>) {
showLoading(context, type.name)
}
fun showLoading(context: Context) {
showLoading(context, DEFAULT_LOADER)
}
fun stopLoading() {
for (dialog in LOADERS) {
if (dialog.isShowing) {
dialog.cancel()
}
}
}
}
}
\ No newline at end of file
package com.rudian.library.ui
import android.content.Context
import com.wang.avi.AVLoadingIndicatorView
import com.wang.avi.Indicator
import java.util.*
/**
* Created on 2019-08-20
* Created by xuelimin
*/
class LoaderCreator {
private val LOADING_MAP = WeakHashMap<String, Indicator>()
internal fun create(type: String, context: Context): AVLoadingIndicatorView {
val avLoadingIndicatorView = AVLoadingIndicatorView(context)
if (LOADING_MAP[type] == null) {
val indicator = getIndicator(type)
LOADING_MAP[type] = indicator
}
avLoadingIndicatorView.indicator = LOADING_MAP[type]
return avLoadingIndicatorView
}
private fun getIndicator(name: String?): Indicator? {
if (name == null || name.isEmpty()) {
return null
}
val drawableClassName = StringBuilder()
if (!name.contains(".")) {
val defaultPackageName = AVLoadingIndicatorView::class.java.getPackage()!!.name
drawableClassName.append(defaultPackageName).append(".indicators").append(".")
}
drawableClassName.append(name)
try {
val drawableClass = Class.forName(drawableClassName.toString())
return drawableClass.newInstance() as Indicator
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
}
\ No newline at end of file
package com.rudian.library.ui
/**
* Created on 2019-08-20
* Created by xuelimin
*/
enum class LoaderStyle {
BallPulseIndicator,
BallGridPulseIndicator,
BallClipRotateIndicator,
BallClipRotatePulseIndicator,
SquareSpinIndicator,
BallClipRotateMultipleIndicator,
BallPulseRiseIndicator,
BallRotateIndicator,
CubeTransitionIndicator,
BallZigZagIndicator,
BallZigZagDeflectIndicator,
BallTrianglePathIndicator,
BallScaleIndicator,
LineScaleIndicator,
LineScalePartyIndicator,
BallScaleMultipleIndicator,
BallPulseSyncIndicator,
BallBeatIndicator,
LineScalePulseOutIndicator,
LineScalePulseOutRapidIndicator,
BallScaleRippleIndicator,
BallScaleRippleMultipleIndicator,
BallSpinFadeLoaderIndicator,
LineSpinFadeLoaderIndicator,
TriangleSkewSpinIndicator,
PacmanIndicator,
BallGridBeatIndicator,
SemiCircleSpinIndicator,
}
\ No newline at end of file
package com.rudian.library.ui.loopview
internal class InertiaTimerTask(val loopView: LoopView, val velocityY: Float) : Runnable {
var a: Float = 0.toFloat()
init {
a = Integer.MAX_VALUE.toFloat()
}
override fun run() {
if (a == Integer.MAX_VALUE.toFloat()) {
if (Math.abs(velocityY) > 2000f) {
if (velocityY > 0.0f) {
a = 2000f
} else {
a = -2000f
}
} else {
a = velocityY
}
}
if (Math.abs(a) >= 0.0f && Math.abs(a) <= 20f) {
loopView.cancelFuture()
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_SMOOTH_SCROLL)
return
}
val i = (a * 10f / 1000f).toInt()
val loopview = loopView
loopview.totalScrollY = loopview.totalScrollY - i
if (!loopView.isLoop) {
val itemHeight = loopView.lineSpacingMultiplier * loopView.itemTextHeight
if (loopView.totalScrollY <= ((-loopView.initPosition).toFloat() * itemHeight).toInt()) {
a = 40f
loopView.totalScrollY = ((-loopView.initPosition).toFloat() * itemHeight).toInt()
} else if (loopView.totalScrollY >= ((loopView.items!!.size - 1 - loopView.initPosition).toFloat() * itemHeight).toInt()) {
loopView.totalScrollY = ((loopView.items!!.size - 1 - loopView.initPosition).toFloat() * itemHeight).toInt()
a = -40f
}
}
if (a < 0.0f) {
a = a + 20f
} else {
a = a - 20f
}
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW)
}
}
package com.rudian.library.ui.loopview;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import com.rudian.library.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Created by Weidongjian on 2015/8/18.
*/
public class LoopView extends View {
private float scaleX = 1.05F;
private static final int DEFAULT_TEXT_SIZE = (int) (Resources.getSystem().getDisplayMetrics().density * 15);
private static final float DEFAULT_LINE_SPACE = 1f;
private static final int DEFAULT_VISIBIE_ITEMS = 9;
public enum ACTION {
CLICK, FLING, DRAG
}
private Context context;
Handler handler;
private GestureDetector flingGestureDetector;
OnItemSelectedListener onItemSelectedListener;
// Timer mTimer;
ScheduledExecutorService mExecutor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> mFuture;
private Paint paintOuterText;
private Paint paintCenterText;
private Paint paintIndicator;
List<IndexString> items;
int textSize;
int itemTextHeight;
//文本的高度
int textHeight;
int outerTextColor;
int centerTextColor;
int dividerColor;
float lineSpacingMultiplier;
boolean isLoop;
int firstLineY;
int secondLineY;
int totalScrollY;
int initPosition;
private int selectedItem;
int preCurrentIndex;
int change;
int itemsVisibleCount;
HashMap<Integer,IndexString> drawingStrings;
// HashMap<String,Integer> drawingStr
int measuredHeight;
int measuredWidth;
int halfCircumference;
int radius;
private int mOffset = 0;
private float previousY;
long startTime = 0;
private Rect tempRect = new Rect();
private int paddingLeft, paddingRight;
private Typeface typeface = Typeface.MONOSPACE;
/**
* set text line space, must more than 1
* @param lineSpacingMultiplier
*/
public void setLineSpacingMultiplier(float lineSpacingMultiplier) {
if (lineSpacingMultiplier > 1.0f) {
this.lineSpacingMultiplier = lineSpacingMultiplier;
}
}
/**
* set outer text color
* @param centerTextColor
*/
public void setCenterTextColor(int centerTextColor) {
this.centerTextColor = centerTextColor;
paintCenterText.setColor(centerTextColor);
}
/**
* set center text color
* @param outerTextColor
*/
public void setOuterTextColor(int outerTextColor) {
this.outerTextColor = outerTextColor;
paintOuterText.setColor(outerTextColor);
}
/**
* set divider color
* @param dividerColor
*/
public void setDividerColor(int dividerColor) {
this.dividerColor = dividerColor;
paintIndicator.setColor(dividerColor);
}
/**
* set text typeface
* @param typeface
*/
public void setTypeface(Typeface typeface) {
this.typeface = typeface;
}
public LoopView(Context context) {
super(context);
initLoopView(context, null);
}
public LoopView(Context context, AttributeSet attributeset) {
super(context, attributeset);
initLoopView(context, attributeset);
}
public LoopView(Context context, AttributeSet attributeset, int defStyleAttr) {
super(context, attributeset, defStyleAttr);
initLoopView(context, attributeset);
}
private void initLoopView(Context context, AttributeSet attributeset) {
this.context = context;
handler = new MessageHandler(this);
flingGestureDetector = new GestureDetector(context, new LoopViewGestureListener(this));
flingGestureDetector.setIsLongpressEnabled(false);
TypedArray typedArray = context.obtainStyledAttributes(attributeset, R.styleable.LoopView);
if (typedArray != null) {
textSize = typedArray.getInteger(R.styleable.LoopView_awv_textsize, DEFAULT_TEXT_SIZE);
textSize = (int) (Resources.getSystem().getDisplayMetrics().density * textSize);
lineSpacingMultiplier = typedArray.getFloat(R.styleable.LoopView_awv_lineSpace, DEFAULT_LINE_SPACE);
centerTextColor = typedArray.getColor(R.styleable.LoopView_awv_centerTextColor, 0xff313131);
outerTextColor = typedArray.getColor(R.styleable.LoopView_awv_outerTextColor, 0xffafafaf);
dividerColor = typedArray.getColor(R.styleable.LoopView_awv_dividerTextColor, 0xffc5c5c5);
itemsVisibleCount =
typedArray.getInteger(R.styleable.LoopView_awv_itemsVisibleCount, DEFAULT_VISIBIE_ITEMS);
if (itemsVisibleCount % 2 == 0) {
itemsVisibleCount = DEFAULT_VISIBIE_ITEMS;
}
isLoop = typedArray.getBoolean(R.styleable.LoopView_awv_isLoop, true);
typedArray.recycle();
}
drawingStrings=new HashMap<>();
totalScrollY = 0;
initPosition = -1;
}
/**
* visible item count, must be odd number
*
* @param visibleNumber
*/
public void setItemsVisibleCount(int visibleNumber) {
if (visibleNumber % 2 == 0) {
return;
}
if (visibleNumber != itemsVisibleCount) {
itemsVisibleCount = visibleNumber;
drawingStrings=new HashMap<>();
}
}
private void initPaintsIfPosssible() {
if (paintOuterText == null) {
paintOuterText = new Paint();
paintOuterText.setColor(outerTextColor);
paintOuterText.setAntiAlias(true);
paintOuterText.setTypeface(typeface);
paintOuterText.setTextSize(textSize);
}
if (paintCenterText == null) {
paintCenterText = new Paint();
paintCenterText.setColor(centerTextColor);
paintCenterText.setAntiAlias(true);
paintCenterText.setTextScaleX(scaleX);
paintCenterText.setTypeface(typeface);
paintCenterText.setTextSize(textSize);
}
if (paintIndicator == null) {
paintIndicator = new Paint();
paintIndicator.setColor(dividerColor);
paintIndicator.setAntiAlias(true);
}
}
private void remeasure() {
if (items == null || items.isEmpty()) {
return;
}
measuredWidth = getMeasuredWidth();
measuredHeight = getMeasuredHeight();
if (measuredWidth == 0 || measuredHeight == 0) {
return;
}
paddingLeft = getPaddingLeft();
paddingRight = getPaddingRight();
measuredWidth = measuredWidth - paddingRight;
paintCenterText.getTextBounds("\u661F\u671F", 0, 2, tempRect); // 星期
textHeight = tempRect.height();
halfCircumference = (int) (measuredHeight * Math.PI / 2);
itemTextHeight = (int) (halfCircumference / (lineSpacingMultiplier * (itemsVisibleCount - 1)));
radius = measuredHeight / 2;
firstLineY = (int) ((measuredHeight - lineSpacingMultiplier * itemTextHeight) / 2.0F);
secondLineY = (int) ((measuredHeight + lineSpacingMultiplier * itemTextHeight) / 2.0F);
if (initPosition == -1) {
if (isLoop) {
initPosition = (items.size() + 1) / 2;
} else {
initPosition = 0;
}
}
preCurrentIndex = initPosition;
}
void smoothScroll(ACTION action) {
cancelFuture();
if (action == ACTION.FLING || action == ACTION.DRAG) {
float itemHeight = lineSpacingMultiplier * itemTextHeight;
mOffset = (int) ((totalScrollY % itemHeight + itemHeight) % itemHeight);
if ((float) mOffset > itemHeight / 2.0F) {
mOffset = (int) (itemHeight - (float) mOffset);
} else {
mOffset = -mOffset;
}
}
mFuture =
mExecutor.scheduleWithFixedDelay(new SmoothScrollTimerTask(this, mOffset), 0, 10, TimeUnit.MILLISECONDS);
}
protected final void scrollBy(float velocityY) {
cancelFuture();
// change this number, can change fling speed
int velocityFling = 10;
mFuture = mExecutor.scheduleWithFixedDelay(new InertiaTimerTask(this, velocityY), 0, velocityFling,
TimeUnit.MILLISECONDS);
}
public void cancelFuture() {
if (mFuture != null && !mFuture.isCancelled()) {
mFuture.cancel(true);
mFuture = null;
}
}
/**
* set not loop
*/
public void setNotLoop() {
isLoop = false;
}
/**
* set text size in dp
* @param size
*/
public final void setTextSize(float size) {
if (size > 0.0F) {
textSize = (int) (context.getResources().getDisplayMetrics().density * size);
paintOuterText.setTextSize(textSize);
paintCenterText.setTextSize(textSize);
}
}
public final void setInitPosition(int initPosition) {
if (initPosition < 0) {
this.initPosition = 0;
} else {
if (items != null && items.size() > initPosition) {
this.initPosition = initPosition;
}
}
}
public final void setListener(OnItemSelectedListener OnItemSelectedListener) {
onItemSelectedListener = OnItemSelectedListener;
}
public final void setItems(List<String> items) {
this.items = convertData(items);
remeasure();
invalidate();
}
public List<IndexString> convertData(List<String> items){
List<IndexString> data=new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
data.add(new IndexString(i,items.get(i)));
}
return data;
}
public final int getSelectedItem() {
return preCurrentIndex;
}
//
// protected final void scrollBy(float velocityY) {
// Timer timer = new Timer();
// mTimer = timer;
// timer.schedule(new InertiaTimerTask(this, velocityY, timer), 0L, 20L);
// }
protected final void onItemSelected() {
if (onItemSelectedListener != null) {
postDelayed(new OnItemSelectedRunnable(this), 200L);
}
}
/**
* link https://github.com/weidongjian/androidWheelView/issues/10
*
* @param scaleX
*/
public void setScaleX(float scaleX) {
this.scaleX = scaleX;
}
/**
* set current item position
* @param position
*/
public void setCurrentPosition(int position) {
if (items == null || items.isEmpty()) {
return;
}
int size = items.size();
if (position >= 0 && position < size && position != selectedItem) {
initPosition = position;
totalScrollY = 0;
mOffset = 0;
invalidate();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (items == null || items.isEmpty()) {
return;
}
change = (int) (totalScrollY / (lineSpacingMultiplier * itemTextHeight));
preCurrentIndex = initPosition + change % items.size();
if (!isLoop) {
if (preCurrentIndex < 0) {
preCurrentIndex = 0;
}
if (preCurrentIndex > items.size() - 1) {
preCurrentIndex = items.size() - 1;
}
} else {
if (preCurrentIndex < 0) {
preCurrentIndex = items.size() + preCurrentIndex;
}
if (preCurrentIndex > items.size() - 1) {
preCurrentIndex = preCurrentIndex - items.size();
}
}
int j2 = (int) (totalScrollY % (lineSpacingMultiplier * itemTextHeight));
// put value to drawingString
int k1 = 0;
while (k1 < itemsVisibleCount) {
int l1 = preCurrentIndex - (itemsVisibleCount / 2 - k1);
if (isLoop) {
while (l1 < 0) {
l1 = l1 + items.size();
}
while (l1 > items.size() - 1) {
l1 = l1 - items.size();
}
drawingStrings.put(k1, items.get(l1));
} else if (l1 < 0) {
// drawingStrings[k1] = "";
drawingStrings.put(k1,new IndexString());
} else if (l1 > items.size() - 1) {
// drawingStrings[k1] = "";
drawingStrings.put(k1,new IndexString());
} else {
// drawingStrings[k1] = items.get(l1);
drawingStrings.put(k1,items.get(l1));
}
k1++;
}
canvas.drawLine(paddingLeft, firstLineY, measuredWidth, firstLineY, paintIndicator);
canvas.drawLine(paddingLeft, secondLineY, measuredWidth, secondLineY, paintIndicator);
int i = 0;
while (i < itemsVisibleCount) {
canvas.save();
float itemHeight = itemTextHeight * lineSpacingMultiplier;
double radian = ((itemHeight * i - j2) * Math.PI) / halfCircumference;
if (radian >= Math.PI || radian <= 0) {
canvas.restore();
} else {
int translateY = (int) (radius - Math.cos(radian) * radius - (Math.sin(radian) * itemTextHeight) / 2D);
canvas.translate(0.0F, translateY);
canvas.scale(1.0F, (float) Math.sin(radian));
if (translateY <= firstLineY && itemTextHeight + translateY >= firstLineY) {
// first divider
canvas.save();
canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY);
drawOuterText(canvas, i);
canvas.restore();
canvas.save();
canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight));
drawCenterText(canvas, i);
canvas.restore();
} else if (translateY <= secondLineY && itemTextHeight + translateY >= secondLineY) {
// second divider
canvas.save();
canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY);
drawCenterText(canvas, i);
canvas.restore();
canvas.save();
canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight));
drawOuterText(canvas, i);
canvas.restore();
} else if (translateY >= firstLineY && itemTextHeight + translateY <= secondLineY) {
// center item
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
drawCenterText(canvas, i);
selectedItem = items.indexOf(drawingStrings.get(i));
} else {
// other item
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
drawOuterText(canvas, i);
}
canvas.restore();
}
i++;
}
}
private void drawOuterText(Canvas canvas, int position) {
canvas.drawText(drawingStrings.get(position).string, getTextX(drawingStrings.get(position).string, paintOuterText, tempRect),
getDrawingY(), paintOuterText);
}
private void drawCenterText(Canvas canvas, int position) {
canvas.drawText(drawingStrings.get(position).string, getTextX(drawingStrings.get(position).string, paintOuterText, tempRect),
getDrawingY(), paintCenterText);
}
private int getDrawingY() {
if (itemTextHeight > textHeight) {
return itemTextHeight - ((itemTextHeight - textHeight) / 2);
} else {
return itemTextHeight;
}
}
// text start drawing position
private int getTextX(String a, Paint paint, Rect rect) {
paint.getTextBounds(a, 0, a.length(), rect);
int textWidth = rect.width();
textWidth *= scaleX;
return (measuredWidth - paddingLeft - textWidth) / 2 + paddingLeft;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
initPaintsIfPosssible();
remeasure();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean eventConsumed = flingGestureDetector.onTouchEvent(event);
float itemHeight = lineSpacingMultiplier * itemTextHeight;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTime = System.currentTimeMillis();
cancelFuture();
previousY = event.getRawY();
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_MOVE:
float dy = previousY - event.getRawY();
previousY = event.getRawY();
totalScrollY = (int) (totalScrollY + dy);
if (!isLoop) {
float top = -initPosition * itemHeight;
float bottom = (items.size() - 1 - initPosition) * itemHeight;
if (totalScrollY < top) {
totalScrollY = (int) top;
} else if (totalScrollY > bottom) {
totalScrollY = (int) bottom;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
default:
if (!eventConsumed) {
float y = event.getY();
double l = Math.acos((radius - y) / radius) * radius;
int circlePosition = (int) ((l + itemHeight / 2) / itemHeight);
float extraOffset = (totalScrollY % itemHeight + itemHeight) % itemHeight;
mOffset = (int) ((circlePosition - itemsVisibleCount / 2) * itemHeight - extraOffset);
if ((System.currentTimeMillis() - startTime) > 120) {
smoothScroll(ACTION.DRAG);
} else {
smoothScroll(ACTION.CLICK);
}
}
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
}
invalidate();
return true;
}
class IndexString {
public IndexString(){
this.string="";
}
public IndexString(int index,String str){
this.index=index;this.string=str;
}
private String string;
private int index;
}
}
package com.rudian.library.ui.loopview
import android.view.MotionEvent
internal class LoopViewGestureListener(val loopView: LoopView) : android.view.GestureDetector.SimpleOnGestureListener() {
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
loopView.scrollBy(velocityY)
return true
}
}
package com.rudian.library.ui.loopview
import android.os.Handler
import android.os.Message
internal class MessageHandler(val loopview: LoopView) : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
WHAT_INVALIDATE_LOOP_VIEW -> loopview.invalidate()
WHAT_SMOOTH_SCROLL -> loopview.smoothScroll(LoopView.ACTION.FLING)
WHAT_ITEM_SELECTED -> loopview.onItemSelected()
}
}
companion object {
val WHAT_INVALIDATE_LOOP_VIEW = 1000
val WHAT_SMOOTH_SCROLL = 2000
val WHAT_ITEM_SELECTED = 3000
}
}
package com.rudian.library.ui.loopview
interface OnItemSelectedListener {
fun onItemSelected(index: Int)
}
package com.rudian.library.ui.loopview
internal class OnItemSelectedRunnable(val loopView: LoopView) : Runnable {
override fun run() {
loopView.onItemSelectedListener!!.onItemSelected(loopView.selectedItem)
}
}
package com.rudian.library.ui.loopview
internal class SmoothScrollTimerTask(val loopView: LoopView, var offset: Int) : Runnable {
var realTotalOffset: Int = 0
var realOffset: Int = 0
init {
realTotalOffset = Integer.MAX_VALUE
realOffset = 0
}
override fun run() {
if (realTotalOffset == Integer.MAX_VALUE) {
realTotalOffset = offset
}
realOffset = (realTotalOffset.toFloat() * 0.1f).toInt()
if (realOffset == 0) {
if (realTotalOffset < 0) {
realOffset = -1
} else {
realOffset = 1
}
}
if (Math.abs(realTotalOffset) <= 0) {
loopView.cancelFuture()
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED)
} else {
loopView.totalScrollY = loopView.totalScrollY + realOffset
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW)
realTotalOffset = realTotalOffset - realOffset
}
}
}
package com.rudian.library.ui.recycler
import androidx.annotation.ColorInt
import com.choices.divider.DividerItemDecoration
/**
* Created on 2019-08-28
* Created by 薛立民
*/
class BaseDecoration private constructor(@ColorInt color: Int, size: Int) : DividerItemDecoration() {
init {
setDividerLookup(DividerLookupImpl(color, size))
}
companion object {
fun create(@ColorInt color: Int, size: Int): BaseDecoration {
return BaseDecoration(color, size)
}
}
}
package com.rudian.library.ui.recycler
import java.util.*
/**
* Created on 2019-08-28
* Created by 薛立民
*/
abstract class DataConverter {
protected val ENTITIES = ArrayList<MultipleItemEntity>()
private var mJsonData: String? = null
protected val jsonData: String
get() {
if (mJsonData == null || mJsonData!!.isEmpty()) {
throw NullPointerException("DATA IS NULL")
}
return mJsonData as String
}
abstract fun convert(): ArrayList<MultipleItemEntity>
fun setJsonData(json: String): DataConverter {
this.mJsonData = json
return this
}
}
package com.rudian.library.ui.recycler
import com.choices.divider.Divider
import com.choices.divider.DividerItemDecoration
/**
* Created on 2019-08-28
* Created by 薛立民
*/
class DividerLookupImpl(private val COLOR: Int, private val SIZE: Int) : DividerItemDecoration.DividerLookup {
override fun getVerticalDivider(position: Int): Divider {
return Divider.Builder()
.size(SIZE)
.color(COLOR)
.build()
}
override fun getHorizontalDivider(position: Int): Divider {
return Divider.Builder()
.size(SIZE)
.color(COLOR)
.build()
}
}
package com.rudian.library.ui.recycler
/**
* Created on 2019-08-28
* Created by 薛立民
*/
object ItemType {
val TEXT = 1
val IMAGE = 2
val TEXT_IMAGE = 3
val BANNER = 4
val VERTICAL_MENU_LIST = 5
val HORIZONTAL_MENU_LIST = 6
val VIDEO = 7
val PICTURE = 8
val ITEM_PICTURE = 9
val DIALOG_ITEM = 10
}
package com.rudian.library.ui.recycler
/**
* Created on 2019-08-28
* Created by 薛立民
*/
enum class MultipleFields {
ITEM_TYPE,
TITLE,
TEXT,
IMAGE_URL,
BANNERS,
SPAN_SIZE,
ID,
NAME,
TAG
}
package com.rudian.library.ui.recycler
import com.chad.library.adapter.base.entity.MultiItemEntity
import java.lang.ref.ReferenceQueue
import java.lang.ref.SoftReference
import java.util.*
/**
* Created on 2019-08-29
* Created by xuelimin
*/
class MultipleItemEntity : MultiItemEntity {
private val ITEM_QUENE = ReferenceQueue<LinkedHashMap<Any, Any>>()
private val MULTIPLE_FIELDS = LinkedHashMap<Any, Any>()
private val FIELDS_REFERENCE = SoftReference(MULTIPLE_FIELDS, ITEM_QUENE)
constructor(fields: LinkedHashMap<Any, Any>) {
FIELDS_REFERENCE.get()!!.putAll(fields)
}
override fun getItemType(): Int {
return FIELDS_REFERENCE.get()?.get(MultipleFields.ITEM_TYPE) as Int
}
fun getField(key: Any): Any? {
return FIELDS_REFERENCE.get()?.get(key)
}
fun setField(key: Any, value: Any): MultiItemEntity {
FIELDS_REFERENCE.get()?.set(key, value)
return this
}
companion object {
fun builder(): MultipleItemEntityBuilder {
return MultipleItemEntityBuilder()
}
}
}
package com.rudian.library.ui.recycler
import java.util.*
/**
* Created on 2019-08-28
* Created by 薛立民
*/
class MultipleItemEntityBuilder internal constructor() {
init {
FIELDS.clear()
}
fun setItemType(itemType: Int): MultipleItemEntityBuilder {
FIELDS[MultipleFields.ITEM_TYPE] = itemType
return this
}
fun setField(key: Any, value: Any): MultipleItemEntityBuilder {
FIELDS[key] = value
return this
}
fun setFields(fields: LinkedHashMap<*, *>): MultipleItemEntityBuilder {
FIELDS.putAll(fields)
return this
}
fun build(): MultipleItemEntity {
return MultipleItemEntity(FIELDS)
}
companion object {
private val FIELDS = LinkedHashMap<Any, Any>()
}
}
package com.rudian.library.ui.recycler
import android.view.View
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.chad.library.adapter.base.BaseMultiItemQuickAdapter
import com.chad.library.adapter.base.BaseQuickAdapter
import com.rudian.library.R
/**
* Created on 2019-08-28
* Created by 薛立民
*/
open class MultipleRecyclerAdapter : BaseMultiItemQuickAdapter<MultipleItemEntity, MultipleViewHolder>, BaseQuickAdapter.SpanSizeLookup {
// //确保初始化一次banner 防止重复item加载
// private val mIsInitBanner = false
var mItemListener: OnItemClickListener? = null
constructor(data: List<MultipleItemEntity>) : super(data) {
init()
}
fun setOnItemListener(itemListener: OnItemClickListener?) {
mItemListener = itemListener
}
interface OnItemClickListener {
fun onItemClickListener(position: Int, entity: MultipleItemEntity)
}
override fun convert(holder: MultipleViewHolder, entity: MultipleItemEntity) {
val text: String
val imageUrl: String
// final ArrayList<Integer> bannerImages;
when (entity.itemType) {
ItemType.TEXT -> {
text = entity.getField(MultipleFields.TEXT) as String
holder.setText(R.id.text_single, text)
}
ItemType.IMAGE -> {
imageUrl = entity.getField(MultipleFields.IMAGE_URL) as String
Glide.with(mContext)
.load(imageUrl)
.apply(RECYCLER_OPTIONS)
.into(holder.getView<View>(R.id.image_single) as ImageView)
}
ItemType.TEXT_IMAGE -> {
text = entity.getField(MultipleFields.TEXT) as String
imageUrl = entity.getField(MultipleFields.IMAGE_URL) as String
Glide.with(mContext)
.load(imageUrl)
.apply(RECYCLER_OPTIONS)
.into(holder.getView<View>(R.id.image_multiple) as ImageView)
holder.setText(R.id.tv_multiple, text)
}
// case ItemType.BANNER:
// if (!mIsInitBanner) {
// bannerImages = entity.getField(MultipleFields.BANNERS);
// final ConvenientBanner<Integer> convenientBanner = holder.getView(R.id.banner_recycler_item);
// BannerCreator.setDefaultInt(convenientBanner, bannerImages, this);
// mIsInitBanner = true;
// }
// break;
else -> {
}
}
if (mItemListener != null) {
holder.itemView.setOnClickListener {
mItemListener!!.onItemClickListener(holder.layoutPosition, entity)
}
}
}
private fun init() {
//设置不同的item布局
addItemType(ItemType.TEXT, R.layout.item_multiple_text)
addItemType(ItemType.IMAGE, R.layout.item_multiple_image)
addItemType(ItemType.TEXT_IMAGE, R.layout.item_multiple_image_text)
addItemType(ItemType.BANNER, R.layout.item_multiple_banner)
//设置宽度监听
setSpanSizeLookup(this)
openLoadAnimation()
// //多次执行动画
isFirstOnly(false)
}
override fun createBaseViewHolder(view: View): MultipleViewHolder {
return MultipleViewHolder.create(view)
}
override fun getSpanSize(gridLayoutManager: androidx.recyclerview.widget.GridLayoutManager, position: Int): Int {
return data[position].getField(MultipleFields.SPAN_SIZE) as Int
}
companion object {
//设置图片加载策略
val RECYCLER_OPTIONS = RequestOptions()
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.dontAnimate()
fun create(data: List<MultipleItemEntity>): MultipleRecyclerAdapter {
return MultipleRecyclerAdapter(data)
}
fun create(converter: DataConverter): MultipleRecyclerAdapter {
return MultipleRecyclerAdapter(converter.convert())
}
}
}
package com.rudian.library.ui.recycler
import android.view.View
import com.chad.library.adapter.base.BaseViewHolder
/**
* Created on 2018/5/4 14:43
* Created by 薛立民
* TEL 13262933389
*/
class MultipleViewHolder private constructor(view: View) : BaseViewHolder(view) {
companion object {
fun create(view: View): MultipleViewHolder {
return MultipleViewHolder(view)
}
}
}
package com.rudian.library.ui.scanner
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import me.dm7.barcodescanner.core.ViewFinderView
/**
* Created on 2019-09-19
* Created by xuelimin
*/
class HomeBozzViewFinderView : ViewFinderView {
constructor(context: Context) : this(context, null)
constructor(context: Context, attributeSet: AttributeSet?) :super(context, attributeSet){
mSquareViewFinder = true
mBorderPaint.color = Color.YELLOW
mLaserPaint.color = Color.YELLOW
}
}
package com.rudian.library.ui.scanner
import android.content.Context
import android.util.AttributeSet
import me.dm7.barcodescanner.core.IViewFinder
import me.dm7.barcodescanner.zbar.ZBarScannerView
/**
* Created on 2019-09-19
* Created by xuelimin
*/
class ScanView : ZBarScannerView {
constructor(context: Context) : this(context, null)
constructor(context: Context, attributeSet: AttributeSet?) : super(context, attributeSet)
override fun createViewFinderView(context: Context): IViewFinder {
return HomeBozzViewFinderView(context)
}
}
\ No newline at end of file
package com.rudian.library.ui.scanner
import android.os.Bundle
import com.rudian.library.R
import com.rudian.library.delagete.base.HomeBozzDelegate
import com.rudian.library.util.callback.CallbackManager
import com.rudian.library.util.callback.CallbackType
import kotlinx.android.synthetic.main.delegate_scanner.*
import me.dm7.barcodescanner.zbar.Result
import me.dm7.barcodescanner.zbar.ZBarScannerView
/**
* Created on 2019-09-19
* Created by xuelimin
*/
class ScannerDelegate : HomeBozzDelegate(), ZBarScannerView.ResultHandler {
override fun handleResult(result: Result) {
val callback = CallbackManager.instance.getCallback(CallbackType.ON_SCAN)
if (callback != null) {
callback!!.executeCallback(result.contents)
}
setFragmentResult(111122, Bundle())
supportDelegate.pop()
}
override fun onBindView(savedInstanceState: Bundle?) {
back.setOnClickListener {
mActivity.onBackPressed()
}
mScanView.setAutoFocus(true)
mScanView.setResultHandler(this)
}
override fun onBackPressedSupport(): Boolean {
setFragmentResult(111122, Bundle())
return super.onBackPressedSupport()
}
override fun setLayout(): Any {
return R.layout.delegate_scanner
}
override fun onPause() {
super.onPause()
if (mScanView != null) {
mScanView.stopCameraPreview()
mScanView.stopCamera()
}
}
override fun onResume() {
super.onResume()
if (mScanView != null) {
mScanView.startCamera()
}
}
}
\ No newline at end of file
package com.rudian.library.ui.timer
import java.util.TimerTask
/**
* Created on 2018/4/26 15:09
* Created by 薛立民
* TEL 13262933389
*/
class BaserTimerTask(timerListener: ITimerListener) : TimerTask() {
private var mITimerListener: ITimerListener? = null
init {
this.mITimerListener = timerListener
}
override fun run() {
mITimerListener?.onTimer()
}
}
package com.rudian.library.ui.timer
/**
* Created on 2018/4/26 15:10
* Created by 薛立民
* TEL 13262933389
*/
interface ITimerListener {
fun onTimer()
}
package com.rudian.library.util.base64
import com.google.android.gms.common.util.Base64Utils
import java.io.FileInputStream
/**
* Created on 2019-09-02
* Created by xuelimin
*/
class Base64Util {
companion object {
fun GetImageStr(imagePath: String): String {
val inputStream = FileInputStream(imagePath)
val data = ByteArray(inputStream.available())
inputStream.read(data)
inputStream.close()
return Base64Utils.encode(data)
}
fun GetImageencodeUrlSafe(imagePath: String): String {
val inputStream = FileInputStream(imagePath)
val data = ByteArray(inputStream.available())
inputStream.read(data)
inputStream.close()
return Base64Utils.encodeUrlSafe(data)
}
fun GetImageEncode(imagePath: String): String {
val inputStream = FileInputStream(imagePath)
val data = ByteArray(inputStream.available())
inputStream.read(data)
inputStream.close()
return Base64Utils.encode(data)
}
fun GetImageeUrlSafeNoPadding(imagePath: String): String {
val inputStream = FileInputStream(imagePath)
val data = ByteArray(inputStream.available())
inputStream.read(data)
inputStream.close()
return Base64Utils.encodeUrlSafeNoPadding(data)
}
}
}
\ No newline at end of file
package com.rudian.library.util.callback
import java.util.*
/**
* Created on 2019-08-30
* Created by 薛立民
*/
class CallbackManager {
private object Holder {
val INSTANCE = CallbackManager()
}
fun addCallback(tag: Any, callback: IGlobalCallback<Any>): CallbackManager {
CALLBACKS[tag] = callback
return this
}
fun getCallback(tag: Any): IGlobalCallback<Any>? {
return CALLBACKS[tag]
}
companion object {
private val CALLBACKS = WeakHashMap<Any, IGlobalCallback<Any>>()
val instance = Holder.INSTANCE
}
}
package com.rudian.library.util.callback
/**
* Created on 2019-08-30
* Created by 薛立民
*/
enum class CallbackType {
ON_CROP,
TAG_OPEN_PUSH,
TAG_STOP_PUSH,
ON_SCAN
}
package com.rudian.library.util.callback
/**
* Created on 2019-08-30
* Created by 薛立民
*/
interface IGlobalCallback<Any> {
fun executeCallback(args: Any)
}
package com.rudian.library.util.dimen
import com.rudian.library.app.HomeBozz
/**
* Created on 2019-08-20
* Created by xuelimin
*/
internal object DimenUtil {
val screenWidth: Int
get() {
val resources = HomeBozz.getApplicationContext().resources
val dm = resources.displayMetrics
return dm.widthPixels
}
val screenHeight: Int
get() {
val resources = HomeBozz.getApplicationContext().resources
val dm = resources.displayMetrics
return dm.heightPixels
}
}
\ No newline at end of file
package com.rudian.library.util.file
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Typeface
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.webkit.MimeTypeMap
import android.widget.TextView
import com.rudian.library.app.HomeBozz
import com.rudian.library.net.callback.IRequest
import java.io.*
import java.text.SimpleDateFormat
import java.util.*
/**
* Created on 2019-08-20
* Created by xuelimin
*/
class FileUtil {
companion object {
//格式化的模板
private val TIME_FORMAT = "_yyyyMMdd_HHmmss"
private var REQUEST: IRequest? = null
private val SDCARD_DIR =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + "/" + "AutoUpdate" + "/"
} else {
TODO("VERSION.SDK_INT < FROYO")
}
//默认本地上传图片目录
val UPLOAD_PHOTO_DIR = Environment.getExternalStorageDirectory().path + "/a_upload_photos/"
//网页缓存地址
val WEB_CACHE_DIR = Environment.getExternalStorageDirectory().path + "/app_web_cache/"
//系统相机目录
val CAMERA_PHOTO_DIR = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + "/Camera/"
} else {
TODO("VERSION.SDK_INT < FROYO")
}
fun setRequest(request: IRequest) {
REQUEST = request
}
private fun getTimeFormatName(timeFormatHeader: String): String {
val date = Date(System.currentTimeMillis())
//必须要加上单引号
val dateFormat = SimpleDateFormat("'$timeFormatHeader'$TIME_FORMAT", Locale.getDefault())
return dateFormat.format(date)
}
/**
* @param timeFormatHeader 格式化的头(除去时间部分)
* @param extension 后缀名
* @return 返回时间格式化后的文件名
*/
fun getFileNameByTime(timeFormatHeader: String, extension: String): String {
return getTimeFormatName(timeFormatHeader) + "." + extension
}
private fun createDir(sdcardDirName: String): File {
//拼接成SD卡中完整的dir
val dir = "$SDCARD_DIR/$sdcardDirName/"
val fileDir = File(dir)
if (!fileDir.exists()) {
fileDir.mkdirs()
}
return fileDir
}
fun createFile(sdcardDirName: String, fileName: String): File {
return File(createDir(sdcardDirName), fileName)
}
private fun createFileByTime(sdcardDirName: String, timeFormatHeader: String, extension: String): File {
val fileName = getFileNameByTime(timeFormatHeader, extension)
return createFile(sdcardDirName, fileName)
}
//获取文件的MIME
fun getMimeType(filePath: String): String? {
val extension = getExtension(filePath)
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
}
//获取文件的后缀名
fun getExtension(filePath: String): String {
var suffix = ""
val file = File(filePath)
val name = file.name
val idx = name.lastIndexOf('.')
if (idx > 0) {
suffix = name.substring(idx + 1)
}
return suffix
}
/**
* 保存Bitmap到SD卡中
*
* @param dir 目录名,只需要写自己的相对目录名即可
* @param compress 压缩比例 100是不压缩,值约小压缩率越高
* @return 返回该文件
*/
fun saveBitmap(mBitmap: Bitmap, dir: String, compress: Int): File? {
val sdStatus = Environment.getExternalStorageState()
// 检测sd是否可用
if (sdStatus != Environment.MEDIA_MOUNTED) {
return null
}
var fos: FileOutputStream? = null
var bos: BufferedOutputStream? = null
val fileName = createFileByTime(dir, "DOWN_LOAD", "jpg")
try {
fos = FileOutputStream(fileName)
bos = BufferedOutputStream(fos)
mBitmap.compress(Bitmap.CompressFormat.JPEG, compress, bos)// 把数据写入文件
} catch (e: FileNotFoundException) {
e.printStackTrace()
} finally {
try {
bos?.flush()
bos?.close()
//关闭流
fos?.flush()
fos?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
refreshDCIM()
return fileName
}
fun writeToDisk(`is`: InputStream, dir: String, name: String): File {
// final File file = FileUtil.createFile(dir, name);
val file = File(Environment.getExternalStorageDirectory().toString() + "/msc/" + name)
var bis: BufferedInputStream? = null
var fos: FileOutputStream? = null
var bos: BufferedOutputStream? = null
try {
bis = BufferedInputStream(`is`)
fos = FileOutputStream(file)
bos = BufferedOutputStream(fos)
val data = ByteArray(1024 * 4)
var process = 0
var count = -1
while ({ count = bis.read(data);count }() > 0) {
if (REQUEST != null) {
process += count
REQUEST!!.onRequestDowning(process)
}
bos.write(data, 0, count)
}
bos.flush()
fos.flush()
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
bos?.close()
fos?.close()
bis?.close()
`is`.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return file
}
fun writeToDisk(`is`: InputStream, dir: String, prefix: String, extension: String): File {
val file = createFileByTime(dir, prefix, extension)
var bis: BufferedInputStream? = null
var fos: FileOutputStream? = null
var bos: BufferedOutputStream? = null
try {
bis = BufferedInputStream(`is`)
fos = FileOutputStream(file)
bos = BufferedOutputStream(fos)
val data = ByteArray(1024 * 4)
var process = 0
var count: Int = -1
while ({ count = bis.read(data);count }() > 0) {
bos.write(data, 0, count)
if (REQUEST != null) {
process += count
REQUEST!!.onRequestDowning(process)
}
}
bos.flush()
fos.flush()
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
bos?.close()
fos?.close()
bis?.close()
`is`.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return file
}
/**
* 通知系统刷新系统相册,使照片展现出来
*/
private fun refreshDCIM() {
if (Build.VERSION.SDK_INT >= 19) {
//兼容android4.4版本,只扫描存放照片的目录
MediaScannerConnection.scanFile(HomeBozz.getApplicationContext(),
arrayOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path), null, null)
} else {
//扫描整个SD卡来更新系统图库,当文件很多时用户体验不佳,且不适合4.4以上版本
HomeBozz.getApplicationContext().sendBroadcast(Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())))
}
}
/**
* 读取raw目录中的文件,并返回为字符串
*/
fun getRawFile(id: Int): String {
val `is` = HomeBozz.getApplicationContext().resources.openRawResource(id)
val bis = BufferedInputStream(`is`)
val isr = InputStreamReader(bis)
val br = BufferedReader(isr)
val stringBuilder = StringBuilder()
var str = ""
try {
while (({ str = br.readLine();str }) != null) {
stringBuilder.append(str)
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
br.close()
isr.close()
bis.close()
`is`.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return stringBuilder.toString()
}
fun setIconFont(path: String, textView: TextView) {
val typeface = Typeface.createFromAsset(HomeBozz.getApplicationContext().getAssets(), path)
textView.typeface = typeface
}
/**
* 读取assets目录下的文件,并返回字符串
*/
fun getAssetsFile(name: String): String? {
var `is`: InputStream? = null
var bis: BufferedInputStream? = null
var isr: InputStreamReader? = null
var br: BufferedReader? = null
var stringBuilder: StringBuilder? = null
val assetManager = HomeBozz.getApplicationContext().getAssets()
try {
`is` = assetManager.open(name)
bis = BufferedInputStream(`is`!!)
isr = InputStreamReader(bis)
br = BufferedReader(isr)
stringBuilder = StringBuilder()
var str = ""
while ({ str = br.readLine();str } != null) {
stringBuilder.append(str)
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
br?.close()
isr?.close()
bis?.close()
`is`?.close()
assetManager.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return stringBuilder?.toString()
}
fun getRealFilePath(context: Context, uri: Uri?): String? {
if (null == uri) return null
val scheme = uri.scheme
var data: String? = null
if (scheme == null)
data = uri.path
else if (ContentResolver.SCHEME_FILE == scheme) {
data = uri.path
} else if (ContentResolver.SCHEME_CONTENT == scheme) {
val cursor = context.contentResolver.query(uri, arrayOf(MediaStore.Images.ImageColumns.DATA), null, null, null)
if (null != cursor) {
if (cursor.moveToFirst()) {
val index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)
if (index > -1) {
data = cursor.getString(index)
}
}
cursor.close()
}
}
return data
}
}
}
\ No newline at end of file
package com.rudian.library.util.language
import java.security.MessageDigest
import java.util.*
/**
* Created on 2019-08-22
* Created by xuelimin
*/
class Util {
companion object {
fun getLanguage(): String {
return Locale.getDefault().language
}
/**
* 方法一:通过String.substring()方法将最后的三位去掉
*
* 获取精确到秒的时间戳
* @return
*/
fun getSecondTimestamp(): Int {
val timestamp = Date().time.toString()
val length = timestamp.length
return if (length > 3) {
Integer.valueOf(timestamp.substring(0, length - 3))
} else {
0
}
}
fun sha512(str: String): String {
val digest = MessageDigest.getInstance("SHA-512")
val result = digest.digest(str.toByteArray())
return toHex(result)
}
private fun toHex(byteArray: ByteArray): String {
//转成16进制后是32字节
return with(StringBuilder()) {
byteArray.forEach {
val hex = it.toInt() and (0xFF)
val hexStr = Integer.toHexString(hex)
if (hexStr.length == 1) {
append("0").append(hexStr)
} else {
append(hexStr)
}
}
toString()
}
}
}
}
\ No newline at end of file
package com.rudian.library.util.storage
import android.os.Build
import android.preference.PreferenceManager
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.rudian.library.app.HomeBozz
/**
* Created on 2019-08-21
* Created by xuelimin
*/
class Preference {
companion object {
/**
* 提示:
* Activity.getPreferences(int mode)生成 Activity名.xml 用于Activity内部存储
* PreferenceManager.getDefaultSharedPreferences(Context)生成 包名_preferences.xml
* Context.getSharedPreferences(String name,int mode)生成name.xml
*/
private
val appPreference = PreferenceManager.getDefaultSharedPreferences(HomeBozz.getApplicationContext())
private val APP_PREFERENCES_KEY = "profile"
var appProfile: String?
get() = appPreference.getString(APP_PREFERENCES_KEY, null)
set(`val`) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
appPreference
.edit()
.putString(APP_PREFERENCES_KEY, `val`)
.apply()
} else {
TODO("VERSION.SDK_INT < GINGERBREAD")
}
val appProfileJson: JSONObject
get() {
val profile = appProfile
return JSON.parseObject(profile)
}
fun removeAppProfile() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
appPreference
.edit()
.remove(APP_PREFERENCES_KEY)
.apply()
}
}
fun clearAppPreferences() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
appPreference
.edit()
.clear()
.apply()
}
}
fun setAppFlag(key: String, flag: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
appPreference
.edit()
.putBoolean(key, flag)
.apply()
}
}
fun getAppFlag(key: String): Boolean {
return appPreference
.getBoolean(key, false)
}
fun addCustomAppProfile(key: String, `val`: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
appPreference
.edit()
.putString(key, `val`)
.apply()
}
}
fun getCustomAppProfile(key: String): String {
return appPreference.getString(key, "").toString()
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 自下向上滑入 -->
<translate
android:duration="500"
android:fromYDelta="100%p"
android:toYDelta="0" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 自上向下滑出 -->
<translate
android:duration="500"
android:fromYDelta="0"
android:toYDelta="100%p" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners
android:bottomLeftRadius="8dp"
android:bottomRightRadius="8dp"
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners
android:bottomLeftRadius="8dp"
android:bottomRightRadius="8dp"
android:topLeftRadius="0dp"
android:topRightRadius="0dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/bar_top"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_alignParentTop="true"
android:background="#C0C0C2">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/back"
android:layout_width="20dp"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginTop="20dp"
android:paddingTop="20dp"
android:paddingBottom="10dp"
android:src="@drawable/back" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:gravity="center"
android:paddingTop="6dp"
android:text="扫一扫"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"/>
</androidx.appcompat.widget.Toolbar>
<com.rudian.library.ui.scanner.ScanView
android:id="@+id/mScanView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/bar_top" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="250dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mRvDialogContent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.appcompat.widget.LinearLayoutCompat>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@android:color/transparent"
android:orientation="vertical"
android:paddingBottom="10dp">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/photodialog_btn_take"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/btn_border_takephoto"
android:gravity="center"
android:text="拍照"
android:textColor="#323232" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_gravity="center"
android:background="@android:color/transparent"
android:gravity="center" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/photodialog_btn_native"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center"
android:background="@drawable/btn_border_nativephoto"
android:gravity="center"
android:text="本地"
android:textColor="#323232" />
<View
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_gravity="center"
android:background="@android:color/transparent"
android:gravity="center" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/photodialog_btn_cancel"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center"
android:background="@drawable/btn_border"
android:gravity="center"
android:text="取消"
android:textColor="#323232" />
</androidx.appcompat.widget.LinearLayoutCompat>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<com.bigkoo.convenientbanner.ConvenientBanner xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/banner_recycler_item"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@android:color/white" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.AppCompatImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image_single"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_gravity="center"
android:background="@android:color/white" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image_text_single"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@android:color/white"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image_multiple"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="4"
android:background="@android:color/white" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_multiple"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/white"
android:gravity="center"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
</androidx.appcompat.widget.LinearLayoutCompat>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.AppCompatTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text_single"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:background="@android:color/white"
android:gravity="center"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LoopView">
<attr name="awv_textsize" format="integer" />
<attr name="awv_lineSpace" format="float" />
<attr name="awv_centerTextColor" format="color|integer" />
<attr name="awv_outerTextColor" format="color|integer" />
<attr name="awv_dividerTextColor" format="color|integer" />
<attr name="awv_itemsVisibleCount" format="integer" />
<attr name="awv_isLoop" format="boolean" />
<attr name="awv_initialPosition" format="integer" />
<attr name="awv_scaleX" format="float" />
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="delegate_container" type="id" />
</resources>
\ No newline at end of file
<resources>
<string name="app_name">library</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AnimBottom" parent="@android:style/Animation">
<item name="android:windowEnterAnimation">@anim/dialog_bottom_in</item>
<item name="android:windowExitAnimation">@anim/dialog_bottom_out</item>
</style>
<style name="dialog" parent="@android:style/Theme.Dialog">
<!--去掉边框-->
<item name="android:windowFrame">@null</item>
<!--悬浮-->
<item name="android:windowIsFloating">true</item>
<!--半透明-->
<item name="android:windowIsTranslucent">false</item>
<!--不需要标题-->
<item name="android:windowNoTitle">true</item>
<!--背景透明-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--允许模糊-->
<item name="android:backgroundDimEnabled">true</item>
<!--全屏幕-->
<item name="android:windowFullscreen">true</item>
</style>
<style name="ShareDialog" parent="@android:style/Animation.Dialog">
<item name="android:windowAnimationStyle">@style/AnimBottom</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<!-- 设置背景色 透明-->
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 设置是否显示背景 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 设置背景透明度 0 全透明 1 全不透明-->
<item name="android:backgroundDimAmount">0.8</item>
<!-- 设置点击空白消失 -->
<item name="android:windowCloseOnTouchOutside">true</item>
</style>
<!--透明Activity-->
<style name="Theme.AppCompat.Translucent">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:colorBackground">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
<style name="commomDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<!--边框-->
<item name="android:windowIsFloating">true</item>
<!--是否浮现在activity之上-->
<item name="android:windowIsTranslucent">false</item>
<!--半透明-->
<item name="android:windowNoTitle">true</item>
<!--无标题-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--背景透明-->
<item name="android:backgroundDimEnabled">true</item>
<!--模糊-->
</style>
</resources>
\ No newline at end of file
package com.rudian.library;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.0"
defaultConfig {
applicationId "com.rudian.loopview"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
package com.rudian.loopview
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.rudian.loopview", appContext.packageName)
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.loopviewapplication">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".activity.InnerViewActivity"/>
</application>
</manifest>
\ No newline at end of file
package com.example.administrator.loopviewapplication.activity;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.administrator.loopviewapplication.R;
import com.example.administrator.loopviewapplication.loopview.LoopView;
import com.example.administrator.loopviewapplication.loopview.OnItemSelectedListener;
import com.example.administrator.loopviewapplication.utils.global.AppGlobal;
import java.util.Arrays;
public class InnerViewActivity extends AppCompatActivity {
private LoopView lv_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_inner_activity);
findViewById();
initView();
}
public void findViewById() {
lv_view = (LoopView) findViewById(R.id.lv_view);
}
private void initView() {
lv_view.setItems(Arrays.asList(AppGlobal.getStringArray()));
lv_view.setTextSize(18);
lv_view.setItemsVisibleCount(7);
lv_view.setCenterTextColor(getResources().getColor(R.color.c_2bb2ba));
lv_view.setOuterTextColor(getResources().getColor(R.color.c_c5c5c5));
lv_view.setCurrentPosition(5);
//滚动监听
lv_view.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
Toast.makeText(InnerViewActivity.this, "您选择的星座是:" + Arrays.asList(AppGlobal.getStringArray()).get(index), Toast.LENGTH_LONG)
.show();
}
});
}
}
package com.example.administrator.loopviewapplication.activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.RelativeLayout;
import androidx.appcompat.app.AppCompatActivity;
import com.example.administrator.loopviewapplication.R;
import com.example.administrator.loopviewapplication.pickers.DatePicker;
import com.example.administrator.loopviewapplication.pickers.NumberPicker;
import com.example.administrator.loopviewapplication.pickers.SinglePicker;
import com.example.administrator.loopviewapplication.pickers.TimePicker;
import com.example.administrator.loopviewapplication.utils.global.AppGlobal;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TimePicker mTimePicker;
private SinglePicker mSinglePicker;
private DatePicker mDatePicker;
private NumberPicker mNumberPicker;
private RelativeLayout rl_inner_area, rl_constellation_area, rl_time_area, rl_date_area, rl_height_area;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById();
setListener();
}
public void findViewById() {
rl_inner_area = (RelativeLayout) findViewById(R.id.rl_inner_area);
rl_constellation_area = (RelativeLayout) findViewById(R.id.rl_constellation_area);
rl_time_area = (RelativeLayout) findViewById(R.id.rl_time_area);
rl_date_area = (RelativeLayout) findViewById(R.id.rl_date_area);
rl_height_area = (RelativeLayout) findViewById(R.id.rl_height_area);
}
public void setListener() {
rl_inner_area.setOnClickListener(this);
rl_constellation_area.setOnClickListener(this);
rl_time_area.setOnClickListener(this);
rl_date_area.setOnClickListener(this);
rl_height_area.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.rl_inner_area:
startActivity(new Intent(this, InnerViewActivity.class));
break;
case R.id.rl_constellation_area:
//星座选择
mSinglePicker = new SinglePicker(this, AppGlobal.getStringArray());
mSinglePicker.setSelectedTextColor(getResources().getColor(R.color.c_2bb2ba));
mSinglePicker.setUnSelectedTextColor(getResources().getColor(R.color.c_c5c5c5));
mSinglePicker.setDividerLineColor(getResources().getColor(R.color.tab_cut_line));
mSinglePicker.setSelectedIndex(5);
mSinglePicker.setItemsVisibleCount(7);
mSinglePicker.show();
break;
case R.id.rl_time_area:
//时间选择
mTimePicker = new TimePicker(this, AppGlobal.getHourArray(), AppGlobal.getMinArray());
mTimePicker.setWeightEnable(true);
mTimePicker.setWeightWidth(0.5f);
mTimePicker.setItemsVisibleCount(7);
mTimePicker.setSelectedTextColor(getResources().getColor(R.color.c_2bb2ba));
mTimePicker.setUnSelectedTextColor(getResources().getColor(R.color.c_c5c5c5));
mTimePicker.setDividerLineColor(getResources().getColor(R.color.tab_cut_line));
mTimePicker.setHourSelectedIndex(0);
mTimePicker.setMinSelectedIndex(0);
mTimePicker.show();
break;
case R.id.rl_date_area:
//日期选择
mDatePicker = new DatePicker(this);
mDatePicker.setWeightEnable(true);
mDatePicker.setWeightWidth(0.3f);
mDatePicker.setItemsVisibleCount(7);
mDatePicker.setSelectedTextColor(getResources().getColor(R.color.c_2bb2ba));
mDatePicker.setUnSelectedTextColor(getResources().getColor(R.color.c_c5c5c5));
mDatePicker.setDividerLineColor(getResources().getColor(R.color.tab_cut_line));
mDatePicker.setYearSelected("2017-7-24");
mDatePicker.show();
break;
case R.id.rl_height_area:
mNumberPicker = new NumberPicker(this, AppGlobal.getHeightArray(MainActivity.this));
mNumberPicker.setSelectedTextColor(getResources().getColor(R.color.c_2bb2ba));
mNumberPicker.setUnSelectedTextColor(getResources().getColor(R.color.c_c5c5c5));
mNumberPicker.setDividerLineColor(getResources().getColor(R.color.tab_cut_line));
mNumberPicker.setItemsVisibleCount(7);
mNumberPicker.setSelectedIndex("160cm");
mNumberPicker.show();
break;
}
}
}
package com.example.administrator.loopviewapplication.common;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.StyleRes;
public abstract class BaseDialog<V extends View> implements DialogInterface.OnKeyListener{
public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
protected Context mContext;
protected int screenWidthPixels;
protected int screenHeightPixels;
private Dialog dialog;
private FrameLayout contentLayout;
private boolean isPrepared = false;
public BaseDialog(Context mContext) {
this.mContext = mContext;
DisplayMetrics metrics = displayMetrics(mContext);
screenWidthPixels = metrics.widthPixels;
screenHeightPixels = metrics.heightPixels;
initDialog();
}
private static DisplayMetrics dm = null;
public static DisplayMetrics displayMetrics(Context context) {
if (null != dm) {
return dm;
}
DisplayMetrics dm = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(dm);
return dm;
}
private void initDialog() {
contentLayout = new FrameLayout(mContext);
contentLayout.setLayoutParams(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
contentLayout.setFocusable(true);
contentLayout.setFocusableInTouchMode(true);
//contentLayout.setFitsSystemWindows(true);
dialog = new Dialog(mContext);
dialog.setCanceledOnTouchOutside(true);//触摸屏幕取消窗体
dialog.setCancelable(false);//按返回键取消窗体
dialog.setOnKeyListener(this);
Window window = dialog.getWindow();
if (window != null) {
window.setGravity(Gravity.BOTTOM);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
//AndroidRuntimeException: requestFeature() must be called before adding content
window.requestFeature(Window.FEATURE_NO_TITLE);
window.setContentView(contentLayout);
}
setSize(screenWidthPixels, WRAP_CONTENT);
}
public int getScreenWidthPixels() {
return screenWidthPixels;
}
public int getScreenHeightPixels() {
return screenHeightPixels;
}
/**
* 创建弹窗的内容视图
*
* @return the view
*/
protected abstract V makeContentView();
/**
* 固定高度为屏幕的高
*
* @param fillScreen true为全屏
*/
public void setFillScreen(boolean fillScreen) {
if (fillScreen) {
setSize(screenWidthPixels, (int) (screenHeightPixels * 0.85f));
}
}
/**
* 固定高度为屏幕的一半
*
* @param halfScreen true为半屏
*/
public void setHalfScreen(boolean halfScreen) {
if (halfScreen) {
setSize(screenWidthPixels, screenHeightPixels / 2);
}
}
/**
* 位于屏幕何处
*
* @see Gravity
*/
public void setGravity(int gravity) {
Window window = dialog.getWindow();
if (window != null) {
window.setGravity(gravity);
}
if (gravity == Gravity.CENTER) {
//居于屏幕正中间时,宽度不允许填充屏幕
setWidth((int) (screenWidthPixels * 0.7f));
}
}
/**
* 设置弹窗的内容视图之前执行
*/
protected void setContentViewBefore() {
}
/**
* 设置弹窗的内容视图之后执行
*
* @param contentView 弹窗的内容视图
*/
protected void setContentViewAfter(V contentView) {
}
public void setContentView(View view) {
contentLayout.removeAllViews();
contentLayout.addView(view);
}
public void setAnimationStyle(@StyleRes int animRes) {
Window window = dialog.getWindow();
if (window != null) {
window.setWindowAnimations(animRes);
}
}
public void setOnKeyListener(final DialogInterface.OnKeyListener onKeyListener) {
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
BaseDialog.this.onKey(dialog, keyCode, event);
return onKeyListener.onKey(dialog, keyCode, event);
}
});
}
/**
* 设置弹窗的宽和高
*
* @param width 宽
* @param height 高
*/
public void setSize(int width, int height) {
if (width == MATCH_PARENT) {
//360奇酷等手机对话框MATCH_PARENT时两边还会有边距,故强制填充屏幕宽
width = screenWidthPixels;
}
if (width == 0 && height == 0) {
width = screenWidthPixels;
height = WRAP_CONTENT;
} else if (width == 0) {
width = screenWidthPixels;
} else if (height == 0) {
height = WRAP_CONTENT;
}
ViewGroup.LayoutParams params = contentLayout.getLayoutParams();
if (params == null) {
params = new ViewGroup.LayoutParams(width, height);
} else {
params.width = width;
params.height = height;
}
contentLayout.setLayoutParams(params);
}
/**
* 设置弹窗的宽
*
* @param width 宽
* @see #setSize(int, int)
*/
public void setWidth(int width) {
setSize(width, 0);
}
/**
* 设置弹窗的高
*
* @param height 高
* @see #setSize(int, int)
*/
public void setHeight(int height) {
setSize(0, height);
}
/**
* 设置是否需要重新初始化视图,可用于数据刷新
*/
public void setPrepared(boolean prepared) {
isPrepared = prepared;
}
public boolean isShowing() {
return dialog.isShowing();
}
public final void show() {
if (isPrepared) {
dialog.show();
showAfter();
return;
}
setContentViewBefore();
V view = makeContentView();
setContentView(view);// 设置弹出窗体的布局
setContentViewAfter(view);
isPrepared = true;
dialog.show();
showAfter();
}
protected void showAfter() {
}
public void dismiss() {
dialog.dismiss();
}
public boolean onBackPress() {
dismiss();
return false;
}
@Override
public final boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {
onBackPress();
}
return false;
}
public Context getContext() {
return dialog.getContext();
}
public Window getWindow() {
return dialog.getWindow();
}
/**
* 弹框的内容视图
*/
public View getContentView() {
// IllegalStateException: The specified child already has a parent.
// You must call removeView() on the child's parent first.
return contentLayout.getChildAt(0);
}
/**
* 弹框的根视图
*/
public ViewGroup getRootView() {
return contentLayout;
}
}
package com.example.administrator.loopviewapplication.common;
import android.content.Context;
import android.graphics.Color;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.example.administrator.loopviewapplication.R;
import com.example.administrator.loopviewapplication.utils.ConvertUtils;
public abstract class ConfirmDialog<V extends View> extends BaseDialog<View> {
protected boolean topLineVisible = true;
protected int topLineColor = 0xFFDDDDDD;
protected int topLineHeight = 1;//dp
protected int topBackgroundColor = Color.WHITE;
protected int topHeight = 40;//dp
protected int topPadding = 15;//dp
protected boolean cancelVisible = true;
protected CharSequence cancelText = "";
protected CharSequence submitText = "";
protected CharSequence titleText = "";
protected int cancelTextColor = Color.BLACK;
protected int submitTextColor = Color.BLACK;
protected int titleTextColor = Color.BLACK;
protected int pressedTextColor = 0XFF0288CE;
protected int cancelTextSize = 0;
protected int submitTextSize = 0;
protected int titleTextSize = 0;
protected int backgroundColor = Color.WHITE;
private TextView cancelButton, submitButton;
private View titleView;
public ConfirmDialog(Context mContext) {
super(mContext);
cancelText = mContext.getString(android.R.string.cancel);
submitText = mContext.getString(android.R.string.ok);
}
/**
* 设置顶部标题栏下划线颜色
*/
public void setTopLineColor(@ColorInt int topLineColor) {
this.topLineColor = topLineColor;
}
/**
* 设置顶部标题栏下划线高度,单位为dp
*/
public void setTopLineHeight(int topLineHeight) {
this.topLineHeight = topLineHeight;
}
/**
* 设置顶部标题栏背景颜色
*/
public void setTopBackgroundColor(@ColorInt int topBackgroundColor) {
this.topBackgroundColor = topBackgroundColor;
}
/**
* 设置顶部标题栏高度(单位为dp)
*/
public void setTopHeight(@IntRange(from = 10, to = 80) int topHeight) {
this.topHeight = topHeight;
}
/**
* 设置顶部按钮左边及右边边距(单位为dp)
*/
public void setTopPadding(int topPadding) {
this.topPadding = topPadding;
}
/**
* 设置顶部标题栏下划线是否显示
*/
public void setTopLineVisible(boolean topLineVisible) {
this.topLineVisible = topLineVisible;
}
/**
* 设置顶部标题栏取消按钮是否显示
*/
public void setCancelVisible(boolean cancelVisible) {
if (null != cancelButton) {
cancelButton.setVisibility(cancelVisible ? View.VISIBLE : View.GONE);
} else {
this.cancelVisible = cancelVisible;
}
}
/**
* 设置顶部标题栏取消按钮文字
*/
public void setCancelText(CharSequence cancelText) {
if (null != cancelButton) {
cancelButton.setText(cancelText);
} else {
this.cancelText = cancelText;
}
}
/**
* 设置顶部标题栏取消按钮文字
*/
public void setCancelText(@StringRes int textRes) {
setCancelText(mContext.getString(textRes));
}
/**
* 设置顶部标题栏确定按钮文字
*/
public void setSubmitText(CharSequence submitText) {
if (null != submitButton) {
submitButton.setText(submitText);
} else {
this.submitText = submitText;
}
}
/**
* 设置顶部标题栏确定按钮文字
*/
public void setSubmitText(@StringRes int textRes) {
setSubmitText(mContext.getString(textRes));
}
/**
* 设置顶部标题栏标题文字
*/
public void setTitleText(CharSequence titleText) {
if (titleView != null && titleView instanceof TextView) {
((TextView) titleView).setText(titleText);
} else {
this.titleText = titleText;
}
}
/**
* 设置顶部标题栏标题文字
*/
public void setTitleText(@StringRes int textRes) {
setTitleText(mContext.getString(textRes));
}
/**
* 设置顶部标题栏取消按钮文字颜色
*/
public void setCancelTextColor(@ColorInt int cancelTextColor) {
if (null != cancelButton) {
cancelButton.setTextColor(cancelTextColor);
} else {
this.cancelTextColor = cancelTextColor;
}
}
/**
* 设置顶部标题栏确定按钮文字颜色
*/
public void setSubmitTextColor(@ColorInt int submitTextColor) {
if (null != submitButton) {
submitButton.setTextColor(submitTextColor);
} else {
this.submitTextColor = submitTextColor;
}
}
/**
* 设置顶部标题栏标题文字颜色
*/
public void setTitleTextColor(@ColorInt int titleTextColor) {
if (null != titleView && titleView instanceof TextView) {
((TextView) titleView).setTextColor(titleTextColor);
} else {
this.titleTextColor = titleTextColor;
}
}
/**
* 设置按下时的文字颜色
*/
public void setPressedTextColor(int pressedTextColor) {
this.pressedTextColor = pressedTextColor;
}
/**
* 设置顶部标题栏取消按钮文字大小(单位为sp)
*/
public void setCancelTextSize(@IntRange(from = 10, to = 40) int cancelTextSize) {
this.cancelTextSize = cancelTextSize;
}
/**
* 设置顶部标题栏确定按钮文字大小(单位为sp)
*/
public void setSubmitTextSize(@IntRange(from = 10, to = 40) int submitTextSize) {
this.submitTextSize = submitTextSize;
}
/**
* 设置顶部标题栏标题文字大小(单位为sp)
*/
public void setTitleTextSize(@IntRange(from = 10, to = 40) int titleTextSize) {
this.titleTextSize = titleTextSize;
}
/**
* 设置选择器主体背景颜色
*/
public void setBackgroundColor(@ColorInt int backgroundColor) {
this.backgroundColor = backgroundColor;
}
public void setTitleView(View titleView) {
this.titleView = titleView;
}
public View getTitleView() {
if (null == titleView) {
throw new NullPointerException("please call show at first");
}
return titleView;
}
public TextView getCancelButton() {
if (null == cancelButton) {
throw new NullPointerException("please call show at first");
}
return cancelButton;
}
public TextView getSubmitButton() {
if (null == submitButton) {
throw new NullPointerException("please call show at first");
}
return submitButton;
}
/**
* @see #makeHeaderView()
* @see #makeCenterView()
* @see #makeFooterView()
*/
@Override
protected final View makeContentView() {
LinearLayout rootLayout = new LinearLayout(mContext);
rootLayout.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
rootLayout.setBackgroundColor(backgroundColor);
rootLayout.setOrientation(LinearLayout.VERTICAL);
rootLayout.setGravity(Gravity.CENTER);
rootLayout.setPadding(0, 0, 0, 0);
rootLayout.setClipToPadding(false);
/**
* 选择和确定在上面
*/
/* View headerView = makeHeaderView();
if (headerView != null) {
rootLayout.addView(headerView);
}
if (topLineVisible) {
View lineView = new View(activity);
int height = ConvertUtils.toPx(activity, topLineHeight);
lineView.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, height));
lineView.setBackgroundColor(topLineColor);
rootLayout.addView(lineView);
}
LinearLayout.LayoutParams rootParams = new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f);
rootParams.setMargins(0,15,0,15);
rootLayout.addView(makeCenterView(), rootParams);
View footerView = makeFooterView();
if (footerView != null) {
rootLayout.addView(footerView);
}*/
/**
* 选择和确定在底部
*/
LinearLayout.LayoutParams rootParams = new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f);
rootParams.setMargins(0,10,0,10);
rootLayout.addView(makeCenterView(), rootParams);
if (topLineVisible) {
View lineView = new View(mContext);
int height = ConvertUtils.toPx(mContext, topLineHeight);
lineView.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, height));
lineView.setBackgroundColor(topLineColor);
rootLayout.addView(lineView);
}
View headerView = makeHeaderView();
if (headerView != null) {
rootLayout.addView(headerView);
}
View footerView = makeFooterView();
if (footerView != null) {
rootLayout.addView(footerView);
}
return rootLayout;
}
@Nullable
protected View makeHeaderView() {
RelativeLayout topButtonLayout = new RelativeLayout(mContext);
int height = ConvertUtils.toPx(mContext, topHeight);
topButtonLayout.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, height));
//topButtonLayout.setBackgroundColor(topBackgroundColor);
topButtonLayout.setBackgroundColor(mContext.getResources().getColor(R.color.c_2bb2ba));
topButtonLayout.setGravity(Gravity.CENTER_VERTICAL);
cancelButton = new TextView(mContext);
cancelButton.setVisibility(cancelVisible ? View.VISIBLE : View.GONE);
RelativeLayout.LayoutParams cancelParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, MATCH_PARENT);
cancelParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
cancelParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
cancelButton.setLayoutParams(cancelParams);
cancelButton.setBackgroundColor(Color.TRANSPARENT);
cancelButton.setGravity(Gravity.CENTER);
int padding = ConvertUtils.toPx(mContext, topPadding);
cancelButton.setPadding(padding, 0, padding, 0);
if (!TextUtils.isEmpty(cancelText)) {
cancelButton.setText(cancelText);
}
cancelButton.setTextColor(ConvertUtils.toColorStateList(cancelTextColor, pressedTextColor));
if (cancelTextSize != 0) {
cancelButton.setTextSize(cancelTextSize);
}
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onCancel();
}
});
topButtonLayout.addView(cancelButton);
if (null == titleView) {
TextView textView = new TextView(mContext);
RelativeLayout.LayoutParams titleParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
int margin = ConvertUtils.toPx(mContext, topPadding);
titleParams.leftMargin = margin;
titleParams.rightMargin = margin;
titleParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
titleParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
textView.setLayoutParams(titleParams);
textView.setGravity(Gravity.CENTER);
if (!TextUtils.isEmpty(titleText)) {
textView.setText(titleText);
}
textView.setTextColor(titleTextColor);
if (titleTextSize != 0) {
textView.setTextSize(titleTextSize);
}
titleView = textView;
}
topButtonLayout.addView(titleView);
submitButton = new TextView(mContext);
RelativeLayout.LayoutParams submitParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, MATCH_PARENT);
submitParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
submitParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
submitButton.setLayoutParams(submitParams);
submitButton.setBackgroundColor(Color.TRANSPARENT);
submitButton.setGravity(Gravity.CENTER);
submitButton.setPadding(padding, 0, padding, 0);
if (!TextUtils.isEmpty(submitText)) {
submitButton.setText(submitText);
}
submitButton.setTextColor(ConvertUtils.toColorStateList(submitTextColor, pressedTextColor));
if (submitTextSize != 0) {
submitButton.setTextSize(submitTextSize);
}
submitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onSubmit();
}
});
topButtonLayout.addView(submitButton);
return topButtonLayout;
}
@NonNull
protected abstract V makeCenterView();
@Nullable
protected View makeFooterView() {
return null;
}
/*
* 点击确定按钮的回调
* */
protected void onSubmit() {
}
/*
* 点击取消按钮的回调
* */
protected void onCancel() {
}
}
package com.example.administrator.loopviewapplication.loopview;
final class InertiaTimerTask implements Runnable {
float a;
final float velocityY;
final LoopView loopView;
InertiaTimerTask(LoopView loopview, float velocityY) {
super();
loopView = loopview;
this.velocityY = velocityY;
a = Integer.MAX_VALUE;
}
@Override
public final void run() {
if (a == Integer.MAX_VALUE) {
if (Math.abs(velocityY) > 2000F) {
if (velocityY > 0.0F) {
a = 2000F;
} else {
a = -2000F;
}
} else {
a = velocityY;
}
}
if (Math.abs(a) >= 0.0F && Math.abs(a) <= 20F) {
loopView.cancelFuture();
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_SMOOTH_SCROLL);
return;
}
int i = (int) ((a * 10F) / 1000F);
LoopView loopview = loopView;
loopview.totalScrollY = loopview.totalScrollY - i;
if (!loopView.isLoop) {
float itemHeight = loopView.lineSpacingMultiplier * loopView.maxTextHeight;
if (loopView.totalScrollY <= (int) ((float) (-loopView.initPosition) * itemHeight)) {
a = 40F;
loopView.totalScrollY = (int) ((float) (-loopView.initPosition) * itemHeight);
} else if (loopView.totalScrollY >= (int) ((float) (loopView.items.size() - 1 - loopView.initPosition) * itemHeight)) {
loopView.totalScrollY = (int) ((float) (loopView.items.size() - 1 - loopView.initPosition) * itemHeight);
a = -40F;
}
}
if (a < 0.0F) {
a = a + 20F;
} else {
a = a - 20F;
}
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW);
}
}
package com.example.administrator.loopviewapplication.loopview;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import com.example.administrator.loopviewapplication.R;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class LoopView extends View {
private float scaleX = 1.05F;
private static final int DEFAULT_TEXT_SIZE = (int) (Resources.getSystem().getDisplayMetrics().density * 15);
private static final float DEFAULT_LINE_SPACE = 2f;
private static final int DEFAULT_VISIBIE_ITEMS = 9;
public enum ACTION {
CLICK, FLING, DAGGLE
}
private Context context;
Handler handler;
private GestureDetector flingGestureDetector;
OnItemSelectedListener onItemSelectedListener;
// Timer mTimer;
ScheduledExecutorService mExecutor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> mFuture;
private Paint paintOuterText;
private Paint paintCenterText;
private Paint paintIndicator;
List<String> items;
int textSize;
int maxTextHeight;
int outerTextColor;
int centerTextColor;
int dividerColor;
float lineSpacingMultiplier;
boolean isLoop;
int firstLineY;
int secondLineY;
int totalScrollY;
int initPosition;
private int selectedItem;
int preCurrentIndex;
int change;
int itemsVisibleCount;
String[] drawingStrings;
int measuredHeight;
int measuredWidth;
int halfCircumference;
int radius;
private int mOffset = 0;
private float previousY;
long startTime = 0;
private Rect tempRect = new Rect();
private int paddingLeft, paddingRight;
/**
* set text line space, must more than 1
* @param lineSpacingMultiplier
*/
public void setLineSpacingMultiplier(float lineSpacingMultiplier) {
if (lineSpacingMultiplier > 1.0f) {
this.lineSpacingMultiplier = lineSpacingMultiplier;
}
}
/**
* set outer text color
* @param centerTextColor
*/
public void setCenterTextColor(int centerTextColor) {
this.centerTextColor = centerTextColor;
paintCenterText.setColor(centerTextColor);
}
/**
* set center text color
* @param outerTextColor
*/
public void setOuterTextColor(int outerTextColor) {
this.outerTextColor = outerTextColor;
paintOuterText.setColor(outerTextColor);
}
/**
* set divider color
* @param dividerColor
*/
public void setDividerColor(int dividerColor) {
this.dividerColor = dividerColor;
paintIndicator.setColor(dividerColor);
}
public LoopView(Context context) {
super(context);
initLoopView(context, null);
}
public LoopView(Context context, AttributeSet attributeset) {
super(context, attributeset);
initLoopView(context, attributeset);
}
public LoopView(Context context, AttributeSet attributeset, int defStyleAttr) {
super(context, attributeset, defStyleAttr);
initLoopView(context, attributeset);
}
private void initLoopView(Context context, AttributeSet attributeset) {
this.context = context;
handler = new MessageHandler(this);
flingGestureDetector = new GestureDetector(context, new LoopViewGestureListener(this));
flingGestureDetector.setIsLongpressEnabled(false);
TypedArray typedArray = context.obtainStyledAttributes(attributeset, R.styleable.androidWheelView);
textSize = typedArray.getInteger(R.styleable.androidWheelView_awv_textsize, DEFAULT_TEXT_SIZE);
textSize = (int) (Resources.getSystem().getDisplayMetrics().density * textSize);
lineSpacingMultiplier = typedArray.getFloat(R.styleable.androidWheelView_awv_lineSpace, DEFAULT_LINE_SPACE);
centerTextColor = typedArray.getInteger(R.styleable.androidWheelView_awv_centerTextColor, context.getResources().getColor(R.color.c_2bb2ba));
outerTextColor = typedArray.getInteger(R.styleable.androidWheelView_awv_outerTextColor, context.getResources().getColor(R.color.c_c5c5c5));
dividerColor = typedArray.getInteger(R.styleable.androidWheelView_awv_dividerTextColor, context.getResources().getColor(R.color.tab_cut_line));
itemsVisibleCount =
typedArray.getInteger(R.styleable.androidWheelView_awv_itemsVisibleCount, DEFAULT_VISIBIE_ITEMS);
if (itemsVisibleCount % 2 == 0) {
itemsVisibleCount = DEFAULT_VISIBIE_ITEMS;
}
isLoop = typedArray.getBoolean(R.styleable.androidWheelView_awv_isLoop, true);
typedArray.recycle();
drawingStrings = new String[itemsVisibleCount];
totalScrollY = 0;
initPosition = -1;
initPaints();
}
/**
* visible item count, must be odd number
*
* @param visibleNumber
*/
public void setItemsVisibleCount(int visibleNumber) {
if (visibleNumber % 2 == 0) {
return;
}
if (visibleNumber != itemsVisibleCount) {
itemsVisibleCount = visibleNumber;
drawingStrings = new String[itemsVisibleCount];
}
}
private void initPaints() {
paintOuterText = new Paint();
paintOuterText.setColor(outerTextColor);
paintOuterText.setAntiAlias(true);
paintOuterText.setTypeface(Typeface.MONOSPACE);
paintOuterText.setTextSize(textSize);
paintCenterText = new Paint();
paintCenterText.setColor(centerTextColor);
paintCenterText.setAntiAlias(true);
paintCenterText.setTextScaleX(scaleX);
paintCenterText.setTypeface(Typeface.MONOSPACE);
paintCenterText.setTextSize(textSize);
paintIndicator = new Paint();
paintIndicator.setColor(dividerColor);
paintIndicator.setAntiAlias(true);
}
private void remeasure() {
if (items == null) {
return;
}
measuredWidth = getMeasuredWidth();
measuredHeight = getMeasuredHeight();
if (measuredWidth == 0 || measuredHeight == 0) {
return;
}
paddingLeft = getPaddingLeft();
paddingRight = getPaddingRight();
measuredWidth = measuredWidth - paddingRight;
paintCenterText.getTextBounds("\u661F\u671F", 0, 2, tempRect); // 星期
maxTextHeight = tempRect.height();
halfCircumference = (int) (measuredHeight * Math.PI / 2);
maxTextHeight = (int) (halfCircumference / (lineSpacingMultiplier * (itemsVisibleCount - 1)));
radius = measuredHeight / 2;
firstLineY = (int) ((measuredHeight - lineSpacingMultiplier * maxTextHeight) / 2.0F);
secondLineY = (int) ((measuredHeight + lineSpacingMultiplier * maxTextHeight) / 2.0F);
if (initPosition == -1) {
if (isLoop) {
initPosition = (items.size() + 1) / 2;
} else {
initPosition = 0;
}
}
preCurrentIndex = initPosition;
}
void smoothScroll(ACTION action) {
cancelFuture();
if (action == ACTION.FLING || action == ACTION.DAGGLE) {
float itemHeight = lineSpacingMultiplier * maxTextHeight;
mOffset = (int) ((totalScrollY % itemHeight + itemHeight) % itemHeight);
if ((float) mOffset > itemHeight / 2.0F) {
mOffset = (int) (itemHeight - (float) mOffset);
} else {
mOffset = -mOffset;
}
}
mFuture =
mExecutor.scheduleWithFixedDelay(new SmoothScrollTimerTask(this, mOffset), 0, 10, TimeUnit.MILLISECONDS);
}
protected final void scrollBy(float velocityY) {
cancelFuture();
// change this number, can change fling speed
int velocityFling = 10;
mFuture = mExecutor.scheduleWithFixedDelay(new InertiaTimerTask(this, velocityY), 0, velocityFling,
TimeUnit.MILLISECONDS);
}
public void cancelFuture() {
if (mFuture != null && !mFuture.isCancelled()) {
mFuture.cancel(true);
mFuture = null;
}
}
/**
* set not loop
*/
public void setNotLoop() {
isLoop = false;
}
/**
* set text size in dp
* @param size
*/
public final void setTextSize(float size) {
if (size > 0.0F) {
textSize = (int) (context.getResources().getDisplayMetrics().density * size);
paintOuterText.setTextSize(textSize);
paintCenterText.setTextSize(textSize);
}
}
public final void setInitPosition(int initPosition) {
if (initPosition < 0) {
this.initPosition = 0;
} else {
if (items != null && items.size() > initPosition) {
this.initPosition = initPosition;
}
}
}
public final void setListener(OnItemSelectedListener OnItemSelectedListener) {
onItemSelectedListener = OnItemSelectedListener;
}
public final void setItems(List<String> items) {
this.items = items;
remeasure();
invalidate();
}
public final int getSelectedItem() {
return selectedItem;
}
//
// protected final void scrollBy(float velocityY) {
// Timer timer = new Timer();
// mTimer = timer;
// timer.schedule(new InertiaTimerTask(this, velocityY, timer), 0L, 20L);
// }
protected final void onItemSelected() {
if (onItemSelectedListener != null) {
postDelayed(new OnItemSelectedRunnable(this), 200L);
}
}
/**
* link https://github.com/weidongjian/androidWheelView/issues/10
*
* @param scaleX
*/
public void setScaleX(float scaleX) {
this.scaleX = scaleX;
}
/**
* set current item position
* @param position
*/
public void setCurrentPosition(int position) {
if (items == null || items.isEmpty()) {
return;
}
int size = items.size();
if (position >= 0 && position < size) {
initPosition = position;
totalScrollY = 0;
mOffset = 0;
invalidate();
}
}
@Override
protected void onDraw(Canvas canvas) {
if (items == null) {
return;
}
change = (int) (totalScrollY / (lineSpacingMultiplier * maxTextHeight));
preCurrentIndex = initPosition + change % items.size();
if (!isLoop) {
if (preCurrentIndex < 0) {
preCurrentIndex = 0;
}
if (preCurrentIndex > items.size() - 1) {
preCurrentIndex = items.size() - 1;
}
} else {
if (preCurrentIndex < 0) {
preCurrentIndex = items.size() + preCurrentIndex;
}
if (preCurrentIndex > items.size() - 1) {
preCurrentIndex = preCurrentIndex - items.size();
}
}
int j2 = (int) (totalScrollY % (lineSpacingMultiplier * maxTextHeight));
// put value to drawingString
int k1 = 0;
while (k1 < itemsVisibleCount) {
int l1 = preCurrentIndex - (itemsVisibleCount / 2 - k1);
if (isLoop) {
while (l1 < 0) {
l1 = l1 + items.size();
}
while (l1 > items.size() - 1) {
l1 = l1 - items.size();
}
drawingStrings[k1] = items.get(l1);
} else if (l1 < 0) {
drawingStrings[k1] = "";
} else if (l1 > items.size() - 1) {
drawingStrings[k1] = "";
} else {
drawingStrings[k1] = items.get(l1);
}
k1++;
}
canvas.drawLine(paddingLeft, firstLineY, measuredWidth, firstLineY, paintIndicator);
canvas.drawLine(paddingLeft, secondLineY, measuredWidth, secondLineY, paintIndicator);
int i = 0;
while (i < itemsVisibleCount) {
canvas.save();
float itemHeight = maxTextHeight * lineSpacingMultiplier;
double radian = ((itemHeight * i - j2) * Math.PI) / halfCircumference;
if (radian >= Math.PI || radian <= 0) {
canvas.restore();
} else {
int translateY = (int) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D);
canvas.translate(0.0F, translateY);
canvas.scale(1.0F, (float) Math.sin(radian));
if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) {
// first divider
canvas.save();
canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY);
canvas.drawText(drawingStrings[i], getTextX(drawingStrings[i], paintOuterText, tempRect),
maxTextHeight, paintOuterText);
canvas.restore();
canvas.save();
canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight));
canvas.drawText(drawingStrings[i], getTextX(drawingStrings[i], paintCenterText, tempRect),
maxTextHeight, paintCenterText);
canvas.restore();
} else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) {
// second divider
canvas.save();
canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY);
canvas.drawText(drawingStrings[i], getTextX(drawingStrings[i], paintCenterText, tempRect),
maxTextHeight, paintCenterText);
canvas.restore();
canvas.save();
canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight));
canvas.drawText(drawingStrings[i], getTextX(drawingStrings[i], paintOuterText, tempRect),
maxTextHeight, paintOuterText);
canvas.restore();
} else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) {
// center item
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
canvas.drawText(drawingStrings[i], getTextX(drawingStrings[i], paintCenterText, tempRect),
maxTextHeight, paintCenterText);
selectedItem = items.indexOf(drawingStrings[i]);
} else {
// other item
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
canvas.drawText(drawingStrings[i], getTextX(drawingStrings[i], paintOuterText, tempRect),
maxTextHeight, paintOuterText);
}
canvas.restore();
}
i++;
}
}
// text start drawing position
private int getTextX(String a, Paint paint, Rect rect) {
paint.getTextBounds(a, 0, a.length(), rect);
int textWidth = rect.width();
textWidth *= scaleX;
return (measuredWidth - paddingLeft - textWidth) / 2 + paddingLeft;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
remeasure();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean eventConsumed = flingGestureDetector.onTouchEvent(event);
float itemHeight = lineSpacingMultiplier * maxTextHeight;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTime = System.currentTimeMillis();
cancelFuture();
previousY = event.getRawY();
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_MOVE:
float dy = previousY - event.getRawY();
previousY = event.getRawY();
totalScrollY = (int) (totalScrollY + dy);
if (!isLoop) {
float top = -initPosition * itemHeight;
float bottom = (items.size() - 1 - initPosition) * itemHeight;
if (totalScrollY < top) {
totalScrollY = (int) top;
} else if (totalScrollY > bottom) {
totalScrollY = (int) bottom;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
default:
if (!eventConsumed) {
float y = event.getY();
double l = Math.acos((radius - y) / radius) * radius;
int circlePosition = (int) ((l + itemHeight / 2) / itemHeight);
float extraOffset = (totalScrollY % itemHeight + itemHeight) % itemHeight;
mOffset = (int) ((circlePosition - itemsVisibleCount / 2) * itemHeight - extraOffset);
if ((System.currentTimeMillis() - startTime) > 120) {
smoothScroll(ACTION.DAGGLE);
} else {
smoothScroll(ACTION.CLICK);
}
}
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
}
invalidate();
return true;
}
}
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: braces fieldsfirst space lnc
package com.example.administrator.loopviewapplication.loopview;
import android.view.MotionEvent;
// Referenced classes of package com.qingchifan.view:
// LoopView
final class LoopViewGestureListener extends android.view.GestureDetector.SimpleOnGestureListener {
final LoopView loopView;
LoopViewGestureListener(LoopView loopview) {
loopView = loopview;
}
@Override
public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
loopView.scrollBy(velocityY);
return true;
}
}
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: braces fieldsfirst space lnc
package com.example.administrator.loopviewapplication.loopview;
import android.os.Handler;
import android.os.Message;
// Referenced classes of package com.qingchifan.view:
// LoopView
final class MessageHandler extends Handler {
public static final int WHAT_INVALIDATE_LOOP_VIEW = 1000;
public static final int WHAT_SMOOTH_SCROLL = 2000;
public static final int WHAT_ITEM_SELECTED = 3000;
final LoopView loopview;
MessageHandler(LoopView loopview) {
this.loopview = loopview;
}
@Override
public final void handleMessage(Message msg) {
switch (msg.what) {
case WHAT_INVALIDATE_LOOP_VIEW:
loopview.invalidate();
break;
case WHAT_SMOOTH_SCROLL:
loopview.smoothScroll(LoopView.ACTION.FLING);
break;
case WHAT_ITEM_SELECTED:
loopview.onItemSelected();
break;
}
}
}
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: braces fieldsfirst space lnc
package com.example.administrator.loopviewapplication.loopview;
public interface OnItemSelectedListener {
void onItemSelected(int index);
}
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: braces fieldsfirst space lnc
package com.example.administrator.loopviewapplication.loopview;
// Referenced classes of package com.qingchifan.view:
// LoopView, OnItemSelectedListener
final class OnItemSelectedRunnable implements Runnable {
final LoopView loopView;
OnItemSelectedRunnable(LoopView loopview) {
loopView = loopview;
}
@Override
public final void run() {
loopView.onItemSelectedListener.onItemSelected(loopView.getSelectedItem());
}
}
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: braces fieldsfirst space lnc
package com.example.administrator.loopviewapplication.loopview;
final class SmoothScrollTimerTask implements Runnable {
int realTotalOffset;
int realOffset;
int offset;
final LoopView loopView;
SmoothScrollTimerTask(LoopView loopview, int offset) {
this.loopView = loopview;
this.offset = offset;
realTotalOffset = Integer.MAX_VALUE;
realOffset = 0;
}
@Override
public final void run() {
if (realTotalOffset == Integer.MAX_VALUE) {
realTotalOffset = offset;
}
realOffset = (int) ((float) realTotalOffset * 0.1F);
if (realOffset == 0) {
if (realTotalOffset < 0) {
realOffset = -1;
} else {
realOffset = 1;
}
}
if (Math.abs(realTotalOffset) <= 0) {
loopView.cancelFuture();
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED);
} else {
loopView.totalScrollY = loopView.totalScrollY + realOffset;
loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW);
realTotalOffset = realTotalOffset - realOffset;
}
}
}
package com.example.administrator.loopviewapplication.pickers;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import com.example.administrator.loopviewapplication.R;
import com.example.administrator.loopviewapplication.loopview.LoopView;
import com.example.administrator.loopviewapplication.loopview.OnItemSelectedListener;
import com.example.administrator.loopviewapplication.utils.ConvertUtils;
import com.example.administrator.loopviewapplication.utils.global.AppGlobal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
public class DatePicker extends WheelPicker {
private float weightWidth = 0.0f;
private Context mContext;
private int mYearSelect, mMonthSelect, mDaySelect;
private List<String> mYearArray, mMonthArray, mDayArray;
private LoopView mYearVew, mMonthVew, mDayVew;
private static int START_YEAR = 1930, END_YEAR = Calendar.getInstance().get(Calendar.YEAR);
// 添加大小月月份并将其转换为list,方便之后的判断
String[] months_big = {"1月", "3月", "5月", "7月", "8月", "10月", "12月"};
String[] months_little = {"4月", "6月", "9月", "11月"};
final List<String> list_big = Arrays.asList(months_big);
final List<String> list_little = Arrays.asList(months_little);
int thisYear = Calendar.getInstance().get(Calendar.YEAR);
int thisMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
int thisDay = Calendar.getInstance().get(Calendar.DATE);
public DatePicker(Context mContext) {
super(mContext);
this.mContext = mContext;
this.mYearArray = AppGlobal.getYearArray(mContext, START_YEAR, END_YEAR);
this.mMonthArray = AppGlobal.getMonthArray(mContext);
this.mDayArray = AppGlobal.getDayArray(mContext, 1, 31);
}
/**
* 设置view的权重,总权重数为1 ,weightWidth范围(0.0f-1.0f)
*/
public void setWeightWidth(@FloatRange(from = 0, to = 1) float weightWidth) {
if (weightWidth < 0) {
weightWidth = 0;
}
this.weightWidth = weightWidth;
}
/**
* 设置年月日滚轮默认选中
*/
public void setYearSelected(String selected) {
String[] result = selected.split("-");
this.mYearSelect = Arrays.binarySearch(mYearArray.toArray(), result[0] + mContext.getString(R.string.year));
this.mMonthSelect = Arrays.binarySearch(mMonthArray.toArray(), result[1] + mContext.getString(R.string.month));
this.mDaySelect = Arrays.binarySearch(mDayArray.toArray(), result[2] + mContext.getString(R.string.day));
}
@Override
@NonNull
protected View makeCenterView() {
if (mYearArray.size() == 0 || mMonthArray.size() == 0 || mDayArray.size() == 0) {
throw new IllegalArgumentException("please initial items at first, can't be empty");
}
final LinearLayout layout = new LinearLayout(mContext);
layout.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
final LinearLayout.LayoutParams wheelParams = new LinearLayout.LayoutParams(WRAP_CONTENT, mItemsVisibleCount * 45);
if (weightEnable) {
layout.setWeightSum(1);
//按权重分配宽度
wheelParams.weight = weightWidth;
}
//年
mYearVew = new LoopView(mContext);
mYearVew.setItems(mYearArray);
mYearVew.setLayoutParams(wheelParams);
mYearVew.setTextSize(textSize);
mYearVew.setCurrentPosition(mYearSelect);
mYearVew.setItemsVisibleCount(mItemsVisibleCount);
mYearVew.setCenterTextColor(textColorFocus);
mYearVew.setOuterTextColor(textColorNormal);
mYearVew.setDividerColor(lineDividerColor);
layout.addView(mYearVew);
//月
mMonthVew = new LoopView(mContext);
mMonthVew.setItems(mMonthArray);
mMonthVew.setLayoutParams(wheelParams);
mMonthVew.setTextSize(textSize);
mMonthVew.setCurrentPosition(mMonthSelect);
mMonthVew.setItemsVisibleCount(mItemsVisibleCount);
mMonthVew.setCenterTextColor(textColorFocus);
mMonthVew.setOuterTextColor(textColorNormal);
mMonthVew.setDividerColor(lineDividerColor);
layout.addView(mMonthVew);
//日
mDayVew = new LoopView(mContext);
int year = ConvertUtils.removeContent(mYearArray.get(mYearSelect), mContext.getString(R.string.year));
int month = ConvertUtils.removeContent(mMonthArray.get(mMonthSelect), mContext.getString(R.string.month));
// 判断大小月及是否闰年,用来确定"日"的数据
if (list_big.contains(String.valueOf(month + 1))) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 31);
} else if (list_little.contains(String.valueOf(month + 1))) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 30);
} else {
// 闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 29);
} else {
mDayArray = AppGlobal.getDayArray(mContext, 1, 28);
}
}
mDayVew.setItems(mDayArray);
mDayVew.setLayoutParams(wheelParams);
mDayVew.setTextSize(textSize);
mDayVew.setCurrentPosition(mDaySelect);
mDayVew.setItemsVisibleCount(mItemsVisibleCount);
mDayVew.setCenterTextColor(textColorFocus);
mDayVew.setOuterTextColor(textColorNormal);
mDayVew.setDividerColor(lineDividerColor);
layout.addView(mDayVew);
mYearVew.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mYearSelect = index;
int year_num = ConvertUtils.removeContent(mYearArray.get(mYearSelect), mContext.getString(R.string.year));
// 判断大小月及是否闰年,用来确定"日"的数据
if (list_big.contains(mMonthArray.get(mMonthSelect))) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 31);
mDaySelect = 0;
} else if (list_little.contains(mMonthArray.get(mMonthSelect))) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 30);
mDaySelect = 0;
} else {
if ((year_num % 4 == 0 && year_num % 100 != 0) || year_num % 400 == 0) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 29);
mDaySelect = 0;
} else {
mDayArray = AppGlobal.getDayArray(mContext, 1, 28);
mDaySelect = 0;
}
}
mDayVew.setItems(mDayArray);
mDayVew.setLayoutParams(wheelParams);
mDayVew.setTextSize(textSize);
mDayVew.setCurrentPosition(mDaySelect);
mDayVew.setItemsVisibleCount(mItemsVisibleCount);
mDayVew.setCenterTextColor(textColorFocus);
mDayVew.setOuterTextColor(textColorNormal);
mDayVew.setDividerColor(lineDividerColor);
layout.removeAllViews();
layout.addView(mYearVew);
layout.addView(mMonthVew);
layout.addView(mDayVew);
}
});
mMonthVew.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mMonthSelect = index;
int year_num = ConvertUtils.removeContent(mYearArray.get(mYearSelect), mContext.getString(R.string.year));
// 判断大小月及是否闰年,用来确定"日"的数据
if (list_big.contains(mMonthArray.get(mMonthSelect))) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 31);
mDaySelect = 0;
} else if (list_little.contains(mMonthArray.get(mMonthSelect))) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 30);
mDaySelect = 0;
} else {
if ((year_num % 4 == 0 && year_num % 100 != 0) || year_num % 400 == 0) {
mDayArray = AppGlobal.getDayArray(mContext, 1, 29);
mDaySelect = 0;
} else {
mDayArray = AppGlobal.getDayArray(mContext, 1, 28);
mDaySelect = 0;
}
}
mDayVew.setItems(mDayArray);
mDayVew.setLayoutParams(wheelParams);
mDayVew.setTextSize(textSize);
mDayVew.setCurrentPosition(mDaySelect);
mDayVew.setItemsVisibleCount(mItemsVisibleCount);
mDayVew.setCenterTextColor(textColorFocus);
mDayVew.setOuterTextColor(textColorNormal);
mDayVew.setDividerColor(lineDividerColor);
layout.removeAllViews();
layout.addView(mYearVew);
layout.addView(mMonthVew);
layout.addView(mDayVew);
}
});
mDayVew.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mDaySelect = index;
}
});
return layout;
}
@Override
public void onSubmit() {
Toast.makeText(mContext, "您选择的时间是:" + getTime(), Toast.LENGTH_LONG).show();
}
public String getTime() {
int year_num = ConvertUtils.removeContent(mYearArray.get(mYearSelect), mContext.getString(R.string.year));
int month_num = ConvertUtils.removeContent(mMonthArray.get(mMonthSelect), mContext.getString(R.string.month));
int day_num = ConvertUtils.removeContent(mDayArray.get(mDaySelect), mContext.getString(R.string.day));
if (year_num > thisYear
|| (year_num == thisYear && month_num > thisMonth)
|| (year_num == thisYear && month_num == thisMonth && day_num > thisDay)) {
Toast.makeText(mContext.getApplicationContext(), mContext.getString(R.string.select_time_tip), Toast.LENGTH_LONG).show();
return thisYear + "-" + String.format("%02d", thisMonth) + "-" + String.format("%02d", thisDay);
} else {
return year_num + "-" + String.format("%02d", month_num) + "-" + String.format("%02d", day_num);
}
}
}
package com.example.administrator.loopviewapplication.pickers;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.example.administrator.loopviewapplication.loopview.LoopView;
import com.example.administrator.loopviewapplication.loopview.OnItemSelectedListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class NumberPicker extends WheelPicker {
private List<String> dataList = new ArrayList<>();
private LoopView mNumberLoopView;
private int mStringSelected;
public NumberPicker(Context mContext, String[] items) {
this(mContext, Arrays.asList(items));
}
public NumberPicker(Context mContext, List<String> items) {
super(mContext);
setItems(items);
}
/**
* 设置数据项
*/
public void setItems(String[] items) {
setItems(Arrays.asList(items));
}
/**
* 设置数据项
*/
public void setItems(List<String> items) {
if (null == items || items.size() == 0) {
return;
}
this.dataList = items;
}
/**
* 设置滚轮默认选中
*/
public void setSelectedIndex(String selected) {
this.mStringSelected = Arrays.binarySearch(dataList.toArray(), selected);
}
@Override
@NonNull
protected View makeCenterView() {
if (dataList.size() == 0) {
throw new IllegalArgumentException("please initial items at first, can't be empty");
}
LinearLayout layout = new LinearLayout(mContext);
layout.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams wheelParams = new LinearLayout.LayoutParams(WRAP_CONTENT, mItemsVisibleCount * 45);
mNumberLoopView = new LoopView(mContext);
mNumberLoopView.setItems(dataList);
mNumberLoopView.setLayoutParams(wheelParams);
mNumberLoopView.setTextSize(textSize);
mNumberLoopView.setCurrentPosition(mStringSelected);
mNumberLoopView.setItemsVisibleCount(mItemsVisibleCount);
mNumberLoopView.setCenterTextColor(textColorFocus);
mNumberLoopView.setOuterTextColor(textColorNormal);
mNumberLoopView.setDividerColor(lineDividerColor);
layout.addView(mNumberLoopView);
//小时滚动监听
mNumberLoopView.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mStringSelected = index;
}
});
return layout;
}
@Override
public void onSubmit() {
Toast.makeText(mContext, "您选择的身高是:" + dataList.get(mStringSelected), Toast.LENGTH_LONG).show();
}
}
package com.example.administrator.loopviewapplication.pickers;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.example.administrator.loopviewapplication.loopview.LoopView;
import com.example.administrator.loopviewapplication.loopview.OnItemSelectedListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SinglePicker extends WheelPicker {
private List<String> dataList = new ArrayList<>();
private LoopView mSingleLoopView;
private int mStringSelected;
/**
* 小时分钟
*/
public SinglePicker(Context mContext, String[] items) {
this(mContext, Arrays.asList(items));
}
/**
* 小时分钟
*/
public SinglePicker(Context mContext, List<String> items) {
super(mContext);
setItems(items);
}
/**
* 设置数据项
*/
public void setItems(String[] items) {
setItems(Arrays.asList(items));
}
/**
* 设置数据项
*/
public void setItems(List<String> items) {
if (null == items || items.size() == 0) {
return;
}
this.dataList = items;
}
/**
* 设置滚轮默认选中
*/
public void setSelectedIndex(int selected) {
this.mStringSelected = selected;
}
@Override
@NonNull
protected View makeCenterView() {
if (dataList.size() == 0) {
throw new IllegalArgumentException("please initial items at first, can't be empty");
}
LinearLayout layout = new LinearLayout(mContext);
layout.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams wheelParams = new LinearLayout.LayoutParams(WRAP_CONTENT, mItemsVisibleCount * 45);
mSingleLoopView = new LoopView(mContext);
mSingleLoopView.setItems(dataList);
mSingleLoopView.setLayoutParams(wheelParams);
mSingleLoopView.setTextSize(textSize);
mSingleLoopView.setCurrentPosition(mStringSelected);
mSingleLoopView.setItemsVisibleCount(mItemsVisibleCount);
mSingleLoopView.setCenterTextColor(textColorFocus);
mSingleLoopView.setOuterTextColor(textColorNormal);
mSingleLoopView.setDividerColor(lineDividerColor);
layout.addView(mSingleLoopView);
//小时滚动监听
mSingleLoopView.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mStringSelected = index;
Toast.makeText(mContext, "您选择的星座是:" + dataList.get(mStringSelected), Toast.LENGTH_LONG).show();
}
});
return layout;
}
@Override
public void onSubmit() {
Toast.makeText(mContext, "您选择的星座是:" + dataList.get(mStringSelected), Toast.LENGTH_LONG).show();
}
}
package com.example.administrator.loopviewapplication.pickers;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import com.example.administrator.loopviewapplication.loopview.LoopView;
import com.example.administrator.loopviewapplication.loopview.OnItemSelectedListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TimePicker extends WheelPicker {
private List<String> hourItems = new ArrayList<>();
private List<String> minItems = new ArrayList<>();
private LoopView mHourLoopView, mMinLoopView;
private float weightWidth = 0.0f;
private int mHourSelected;
private int mMinSelected;
/**
* 小时分钟
*/
public TimePicker(Context mContext, String[] hourItems, String[] minItems) {
this(mContext, Arrays.asList(hourItems), Arrays.asList(minItems));
}
/**
* 小时分钟
*/
public TimePicker(Context mContext, List<String> hourItems, List<String> minItems) {
super(mContext);
setHourItems(hourItems);
setMinItems(minItems);
}
/**
* 设置小时数据项
*/
public void setHourItems(String[] items) {
setHourItems(Arrays.asList(items));
}
/**
* 设置数据项
*/
public void setHourItems(List<String> items) {
if (null == items || items.size() == 0) {
return;
}
this.hourItems = items;
}
/**
* 设置分钟数据项
*/
public void setMinItems(String[] items) {
setMinItems(Arrays.asList(items));
}
/**
* 设置数据项
*/
public void setMinItems(List<String> items) {
if (null == items || items.size() == 0) {
return;
}
this.minItems = items;
}
/**
* 设置小时默认选中
*/
public void setHourSelectedIndex(int selected) {
this.mHourSelected = selected;
}
/**
* 设置分钟默认选中
*/
public void setMinSelectedIndex(int selected) {
this.mMinSelected = selected;
}
/**
* 设置view的权重,总权重数为1 ,weightWidth范围(0.0f-1.0f)
*/
public void setWeightWidth(@FloatRange(from = 0, to = 1) float weightWidth) {
if (weightWidth < 0) {
weightWidth = 0;
}
this.weightWidth = weightWidth;
}
@Override
@NonNull
protected View makeCenterView() {
if (hourItems.size() == 0 || minItems.size() == 0) {
throw new IllegalArgumentException("please initial items at first, can't be empty");
}
LinearLayout layout = new LinearLayout(mContext);
layout.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams wheelParams = new LinearLayout.LayoutParams(WRAP_CONTENT, mItemsVisibleCount * 45);
if (weightEnable) {
layout.setWeightSum(1);
//按权重分配宽度
wheelParams.weight = weightWidth;
}
mHourLoopView = new LoopView(mContext);
mHourLoopView.setItems(hourItems);
mHourLoopView.setLayoutParams(wheelParams);
mHourLoopView.setTextSize(textSize);
mHourLoopView.setCurrentPosition(mHourSelected);
mHourLoopView.setItemsVisibleCount(mItemsVisibleCount);
mHourLoopView.setCenterTextColor(textColorFocus);
mHourLoopView.setOuterTextColor(textColorNormal);
mHourLoopView.setDividerColor(lineDividerColor);
layout.addView(mHourLoopView);
//小时滚动监听
mHourLoopView.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mHourSelected = index;
}
});
TextView labelView = new TextView(mContext);
labelView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
labelView.setTextColor(textColorFocus);
labelView.setTextSize(textSize);
labelView.setText(":");
layout.addView(labelView);
mMinLoopView = new LoopView(mContext);
mMinLoopView.setItems(minItems);
mMinLoopView.setLayoutParams(wheelParams);
mMinLoopView.setTextSize(textSize);
mMinLoopView.setCurrentPosition(mMinSelected);
mMinLoopView.setItemsVisibleCount(mItemsVisibleCount);
mMinLoopView.setCenterTextColor(textColorFocus);
mMinLoopView.setOuterTextColor(textColorNormal);
mMinLoopView.setDividerColor(lineDividerColor);
layout.addView(mMinLoopView);
//分钟滚动监听
mMinLoopView.setListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mMinSelected = index;
}
});
return layout;
}
@Override
public void onSubmit() {
Toast.makeText(mContext, "您选择的时间是:" + hourItems.get(mHourSelected) + ":" + minItems.get(mMinSelected), Toast.LENGTH_LONG).show();
}
}
package com.example.administrator.loopviewapplication.pickers;
import android.content.Context;
import android.view.View;
import androidx.annotation.ColorInt;
import com.example.administrator.loopviewapplication.R;
import com.example.administrator.loopviewapplication.common.ConfirmDialog;
public abstract class WheelPicker extends ConfirmDialog<View> {
protected int textSize = 18;
protected int mItemsVisibleCount = 5;
protected int textColorNormal = mContext.getResources().getColor(R.color.c_c5c5c5);
protected int textColorFocus = mContext.getResources().getColor(R.color.c_2bb2ba);
protected int lineDividerColor = mContext.getResources().getColor(R.color.tab_cut_line);
private View contentView;
protected boolean weightEnable = false;
public WheelPicker(Context mContext) {
super(mContext);
}
/**
* 设置文字大小
*/
public void setTextSize(int textSize) {
this.textSize = textSize;
}
public void setItemsVisibleCount(int count) {
this.mItemsVisibleCount = count;
}
/**
* 设置未选中文字颜色
*/
public void setUnSelectedTextColor(@ColorInt int unSelectedTextColor) {
this.textColorNormal = unSelectedTextColor;
}
/**
* 设置选中文字颜色
*/
public void setSelectedTextColor(@ColorInt int selectedTextColor) {
this.textColorFocus = selectedTextColor;
}
/**
* 设置分割线颜色
*/
public void setDividerLineColor(@ColorInt int lineDividerColor) {
this.lineDividerColor = lineDividerColor;
}
/**
*
* 线性布局设置是否启用权重
* true 启用 false 自适应width
*/
public void setWeightEnable(boolean weightEnable) {
this.weightEnable = weightEnable;
}
/**
* 得到选择器视图,可内嵌到其他视图容器
*/
@Override
public View getContentView() {
if (null == contentView) {
contentView = makeCenterView();
}
return contentView;
}
}
package com.example.administrator.loopviewapplication.utils;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.util.TypedValue;
import androidx.annotation.ColorInt;
public class ConvertUtils {
/**
* dp转换为px
*/
public static int toPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
int pxValue = (int) (dpValue * scale + 0.5f);
return pxValue;
}
public static int toPx(float dpValue) {
Resources resources = Resources.getSystem();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, resources.getDisplayMetrics());
return (int) px;
}
public static ColorStateList toColorStateList(@ColorInt int normalColor, @ColorInt int pressedColor,
@ColorInt int focusedColor, @ColorInt int unableColor) {
int[] colors = new int[]{pressedColor, focusedColor, normalColor, focusedColor, unableColor, normalColor};
int[][] states = new int[6][];
states[0] = new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled};
states[1] = new int[]{android.R.attr.state_enabled, android.R.attr.state_focused};
states[2] = new int[]{android.R.attr.state_enabled};
states[3] = new int[]{android.R.attr.state_focused};
states[4] = new int[]{android.R.attr.state_window_focused};
states[5] = new int[]{};
return new ColorStateList(states, colors);
}
public static ColorStateList toColorStateList(@ColorInt int normalColor, @ColorInt int pressedColor) {
return toColorStateList(normalColor, pressedColor, pressedColor, normalColor);
}
public static Integer removeContent(String content, String str) {
String result = content.replaceAll(str, "");
return Integer.parseInt(result);
}
}
package com.example.administrator.loopviewapplication.utils.global;
import android.content.Context;
import com.example.administrator.loopviewapplication.R;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2016/11/23.
* 全局方法
*/
public class AppGlobal {
public static String[] getHourArray() {
String[] hourArray = new String[24];
for (int i = 0; i < 24; i++) {
hourArray[i] = String.format("%02d", i);
}
return hourArray;
}
public static String[] getMinArray() {
String[] minArray = new String[60];
for (int i = 0; i < 60; i++) {
minArray[i] = String.format("%02d", i);
}
return minArray;
}
public static List<String> getYearArray(Context mContext, int start, int end) {
List<String> dataList = new ArrayList<>();
for (int i = 0; i < end - start + 1; i++) {
dataList.add((i + start) + mContext.getString(R.string.year));
}
return dataList;
}
public static List<String> getMonthArray(Context mContext) {
List<String> dataList = new ArrayList<>();
for (int i = 0; i < 12; i++) {
dataList.add((i + 1) + mContext.getString(R.string.month));
}
return dataList;
}
public static List<String> getDayArray(Context mContext, int start, int end) {
List<String> dataList = new ArrayList<>();
for (int i = 0; i < end - start + 1; i++) {
dataList.add((i + start) + mContext.getString(R.string.day));
}
return dataList;
}
public static String[] getStringArray() {
String[] dayArray = new String[]{
"水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座",
"狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座"
};
return dayArray;
}
public static List<String> getHeightArray(Context mContext) {
List<String> dataList = new ArrayList<>();
for (int i = 100; i < 250; i++) {
dataList.add(i + mContext.getString(R.string.cm));
}
return dataList;
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_inner_area"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="40dp"
android:background="@color/c_2bb2ba">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="内嵌页面"
android:textColor="@color/c_ffffff"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_constellation_area"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:background="@color/c_2bb2ba">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="星座选择"
android:textColor="@color/c_ffffff"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_time_area"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:background="@color/c_2bb2ba">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="时间选择"
android:textColor="@color/c_ffffff"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_date_area"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:background="@color/c_2bb2ba">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="日期选择"
android:textColor="@color/c_ffffff"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_height_area"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:background="@color/c_2bb2ba">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="身高选择(身高体重腰围)"
android:textColor="@color/c_ffffff"
android:textSize="18sp" />
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_select_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/c_2bb2ba"
android:textSize="20sp" />
<com.example.administrator.loopviewapplication.loopview.LoopView
android:id="@+id/lv_view"
android:layout_width="wrap_content"
android:layout_height="140dp"
android:layout_centerInParent="true"
android:orientation="vertical" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="androidWheelView">
<attr name="awv_textsize" format="integer" />
<attr name="awv_lineSpace" format="float" />
<attr name="awv_centerTextColor" format="integer" />
<attr name="awv_outerTextColor" format="integer" />
<attr name="awv_dividerTextColor" format="integer" />
<attr name="awv_itemsVisibleCount" format="integer" />
<attr name="awv_isLoop" format="boolean" />
<attr name="awv_initialPosition" format="integer" />
<attr name="awv_scaleX" format="float" />
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="tab_cut_line">#E5E5E5</color> <!-- 标题分割线 -->
<color name="c_2bb2ba">#2BB2BA</color>
<color name="c_c5c5c5">#C5C5C5</color>
<color name="c_ffffff">#FFFFFF</color>
</resources>
<resources>
<string name="app_name">LoopViewApplication</string>
<string name="year"></string>
<string name="month"></string>
<string name="day"></string>
<string name="cm">cm</string>
<string name="select_time_tip">选择的时间不能超过当前时间</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
package com.rudian.loopview
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment