This commit is contained in:
2025-11-18 15:12:24 +08:00
parent c173c425ce
commit a7d2035e70
1361 changed files with 367452 additions and 0 deletions
@@ -0,0 +1,35 @@
package cn.shangyu.gdxzExpert.widget;
import android.graphics.Bitmap;
import android.util.Log;
import android.util.LruCache;
import com.android.volley.toolbox.ImageLoader.ImageCache;
public class BitmapCache implements ImageCache {
private LruCache<String, Bitmap> mCache;
public BitmapCache() {
int maxSize = 4 * 1024 * 1024;
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount();
}
};
}
@Override
public Bitmap getBitmap(String url) {
Log.i("leslie", "get cache " + url);
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
Log.i("leslie", "add cache " + url);
if (bitmap != null) {
mCache.put(url, bitmap);
}
}
}
@@ -0,0 +1,349 @@
/*
* Copyright 2014 - 2015 Henning Dodenhof
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.widget.ImageView;
import cn.shangyu.gdxzExpert.R;
/**
* 自定义圆形图片
* @author
*
*/
public class CircleImageView extends ImageView {
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 2;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
private static final boolean DEFAULT_BORDER_OVERLAY = false;
private final RectF mDrawableRect = new RectF();
private final RectF mBorderRect = new RectF();
private final Matrix mShaderMatrix = new Matrix();
private final Paint mBitmapPaint = new Paint();
private final Paint mBorderPaint = new Paint();
private final Paint mFillPaint = new Paint();
private int mBorderColor = DEFAULT_BORDER_COLOR;
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
private int mFillColor = DEFAULT_FILL_COLOR;
private Bitmap mBitmap;
private BitmapShader mBitmapShader;
private int mBitmapWidth;
private int mBitmapHeight;
private float mDrawableRadius;
private float mBorderRadius;
private ColorFilter mColorFilter;
private boolean mReady;
private boolean mSetupPending;
private boolean mBorderOverlay;
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
a.recycle();
init();
}
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
@Override
public ScaleType getScaleType() {
return SCALE_TYPE;
}
@Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
}
}
@Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (adjustViewBounds) {
throw new IllegalArgumentException("adjustViewBounds not supported.");
}
}
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
if (mFillColor != Color.TRANSPARENT) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
}
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
if (mBorderWidth != 0) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(int borderColor) {
if (borderColor == mBorderColor) {
return;
}
mBorderColor = borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
public void setBorderColorResource(int borderColorRes) {
setBorderColor(getContext().getResources().getColor(borderColorRes));
}
public int getFillColor() {
return mFillColor;
}
public void setFillColor(int fillColor) {
if (fillColor == mFillColor) {
return;
}
mFillColor = fillColor;
mFillPaint.setColor(fillColor);
invalidate();
}
public void setFillColorResource(int fillColorRes) {
setFillColor(getContext().getResources().getColor(fillColorRes));
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth == mBorderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
public boolean isBorderOverlay() {
return mBorderOverlay;
}
public void setBorderOverlay(boolean borderOverlay) {
if (borderOverlay == mBorderOverlay) {
return;
}
mBorderOverlay = borderOverlay;
setup();
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mBitmap = bm;
setup();
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
mBitmap = getBitmapFromDrawable(drawable);
setup();
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
setup();
}
@Override
public void setColorFilter(ColorFilter cf) {
if (cf == mColorFilter) {
return;
}
mColorFilter = cf;
mBitmapPaint.setColorFilter(mColorFilter);
invalidate();
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void setup() {
if (!mReady) {
mSetupPending = true;
return;
}
if (getWidth() == 0 && getHeight() == 0) {
return;
}
if (mBitmap == null) {
invalidate();
return;
}
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setAntiAlias(true);
mFillPaint.setColor(mFillColor);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(0, 0, getWidth(), getHeight());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay) {
mDrawableRect.inset(mBorderWidth, mBorderWidth);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
updateShaderMatrix();
invalidate();
}
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
}
@@ -0,0 +1,161 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.RequestCallbackWrapper;
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.netease.nimlib.sdk.nos.NosService;
import com.netease.nimlib.sdk.nos.model.NosThumbParam;
import com.netease.nimlib.sdk.nos.util.NosThumbImageUtil;
import com.netease.nimlib.sdk.robot.model.RobotAttachment;
import androidx.appcompat.widget.AppCompatImageView;
import cn.shangyu.gdxzExpert.R;
import static com.netease.nim.uikit.common.ui.imageview.HeadImageView.DEFAULT_AVATAR_THUMB_SIZE;
public class CircularRectangle extends AppCompatImageView {
float width,height;
public static final int DEFAULT_AVATAR_RES_ID_new = R.drawable.default_news_iv;
public CircularRectangle(Context context) {
super(context);
}
public CircularRectangle(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircularRectangle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (Build.VERSION.SDK_INT < 18) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = getWidth();
height = getHeight();
}
@Override
protected void onDraw(Canvas canvas) {
if (width > 12 && height > 12) {
Path path = new Path();
path.moveTo(12, 0);
path.lineTo(width - 12, 0);
path.quadTo(width, 0, width, 12);
path.lineTo(width, height - 12);
path.quadTo(width, height, width - 12, height);
path.lineTo(12, height);
path.quadTo(0, height, 0, height - 12);
path.lineTo(0, 12);
path.quadTo(0, 0, 12, 0);
canvas.clipPath(path);
}
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
super.onDraw(canvas);
}
/**
* 加载用户头像(默认大小的缩略图)
*
* @param account 用户账号
*/
public void loadBuddyAvatar(String account) {
// NimUIKit.getContactProvider().getAlias(account);
loadAvatar("", NimUIKit.getContactProvider().getAlias(account));
// final UserInfo userInfo = NimUIKit.getUserInfoProvider().getUserInfo(account);
// changeUrlBeforeLoad(null, userInfo != null ? userInfo.getAvatar() : null,
// DEFAULT_AVATAR_RES_ID, DEFAULT_AVATAR_THUMB_SIZE);
}
/**
* 加载用户头像(默认大小的缩略图)
*
* @param message 消息
*/
public void loadBuddyAvatar(IMMessage message) {
String account = message.getFromAccount();
if (message.getMsgType() == MsgTypeEnum.robot) {
RobotAttachment attachment = (RobotAttachment) message.getAttachment();
if (attachment.isRobotSend()) {
account = attachment.getFromRobotAccount();
}
}
loadBuddyAvatar(account);
}
/**
* 加载用户头像(默认大小的缩略图)
*
* @param url 头像地址
*/
public void loadAvatar(String roomId, final String url) {
changeUrlBeforeLoad(roomId, url, DEFAULT_AVATAR_RES_ID_new, DEFAULT_AVATAR_THUMB_SIZE);
}
/**
* 如果图片是上传到云信服务器,并且用户开启了文件安全功能,那么这里可能是短链,需要先换成源链才能下载。
* 如果没有使用云信存储或没开启文件安全,那么不用这样做
*/
private void changeUrlBeforeLoad(String roomId, final String url, final int defaultResId,
final int thumbSize) {
if (TextUtils.isEmpty(url)) {
// avoid useless call
loadImage(url, defaultResId, thumbSize);
} else {
/*
* 若使用网易云信云存储,这里可以设置下载图片的压缩尺寸,生成下载URL
* 如果图片来源是非网易云信云存储,请不要使用NosThumbImageUtil
*/
NIMClient.getService(NosService.class).getOriginUrlFromShortUrl(url).setCallback(
new RequestCallbackWrapper<String>() {
@Override
public void onResult(int code, String result, Throwable exception) {
if (TextUtils.isEmpty(result)) {
result = url;
}
final String thumbUrl = makeAvatarThumbNosUrl(result, thumbSize);
loadImage(thumbUrl, defaultResId, thumbSize);
}
});
}
}
/**
* ImageLoader异步加载
*/
private void loadImage(final String url, final int defaultResId, final int thumbSize) {
RequestOptions requestOptions = new RequestOptions().centerCrop().placeholder(defaultResId)
.error(defaultResId).override(thumbSize,
thumbSize);
Glide.with(getContext().getApplicationContext()).asBitmap().load(url).apply(requestOptions)
.into(this);
}
/**
* 生成头像缩略图NOS URL地址(用作ImageLoader缓存的key)
*/
private static String makeAvatarThumbNosUrl(final String url, final int thumbSize) {
if (TextUtils.isEmpty(url)) {
return url;
}
return thumbSize > 0 ? NosThumbImageUtil.makeImageThumbUrl(url,
NosThumbParam.ThumbType.Crop,
thumbSize, thumbSize) : url;
}
}
@@ -0,0 +1,105 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ExpandableListView;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChildHelper;
/**
* Author: Moos
* E-mail: moosphon@gmail.com
* Date: 18/4/20.
* Desc: 自定义ExpandableListView,解决与CoordinatorLayout滑动冲突问题
*/
public class CommentExpandableListView extends ExpandableListView implements NestedScrollingChild {
private NestedScrollingChildHelper mScrollingChildHelper;
public CommentExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
mScrollingChildHelper = new NestedScrollingChildHelper(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setNestedScrollingEnabled(true);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
mScrollingChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean isNestedScrollingEnabled() {
return mScrollingChildHelper.isNestedScrollingEnabled();
}
@Override
public boolean startNestedScroll(int axes) {
return mScrollingChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mScrollingChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mScrollingChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow) {
return mScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(target, dx, dy, consumed);
}
public void scroll(int groupIndex, int childIndex) {
int position = 0;
for (int i = 0; i < groupIndex; i++) {
position++;
if (isGroupExpanded(i)){
position = position + getExpandableListAdapter().getChildrenCount(i);
}
}
position++;
position = position + childIndex;
super.smoothScrollToPosition(position);
}
}
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2013 The CCP project authors. All Rights Reserved.
*
* Use of this source code is governed by a Beijing Speedtong Information Technology Co.,Ltd license
* that can be found in the LICENSE file in the root of the web site.
*
* http://www.cloopen.com
*
* An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
import cn.shangyu.gdxzExpert.R;
/**带有删除的搜索输入框
* <p>Title: CCPClearEditText</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2014</p>
* <p>Company: Beijing Speedtong Information Technology Co.,Ltd</p>
* @author Jorstin Chan
* @date 2014-4-6
* @version 1.0
*/
public class CustomClearEditText extends EditText implements View.OnTouchListener , View.OnFocusChangeListener{
final Drawable mClear = getResources().getDrawable(R.drawable.search_clear);
/**
* @param context
*/
public CustomClearEditText(Context context) {
super(context);
initCCPClearEditTextRef();
}
/**
* @param context
* @param attrs
*/
public CustomClearEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initCCPClearEditTextRef();
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public CustomClearEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initCCPClearEditTextRef();
}
private void initCCPClearEditTextRef() {
mClear.setBounds(0, 0, mClear.getIntrinsicHeight(), mClear.getIntrinsicHeight());
doClearDrawable();
setHeight(mClear.getIntrinsicHeight() + 5 * getResources().getDimensionPixelSize(R.dimen.OneDPPadding));
setOnTouchListener(this);
addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
doClearDrawable();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
setOnFocusChangeListener(this);
}
/**
*
*/
private void doClearDrawable() {
if("".equals(getText().toString()) || !isFocused()) {
setClearDrawableNull();
return;
}
setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], mClear, getCompoundDrawables()[3]);
}
/**
*
*/
private void setClearDrawableNull() {
setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], null, getCompoundDrawables()[3]);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if(getCompoundDrawables()[2] == null) {
return false;
}
if((event.getAction() != MotionEvent.ACTION_UP)
|| event.getX() <= (getWidth() - getPaddingRight() - mClear.getIntrinsicWidth())) {
return false;
}
getText().clear();
return false;
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
doClearDrawable();
}
}
@@ -0,0 +1,62 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import cn.shangyu.gdxzExpert.R;
/**
*
* 类名称:CustomToast
* 类描述:自定义的吐司
* 创建人:苏三元
* 时间:2015-9-2 上午11:36:57
* 版权:河南商宇科技有限公司--版权所有 (c) 2015
*
*/
public class CustomToast extends Toast {
private TextView textView;
private String text;
private View view;
private int time;
private Context context;
/**
*
* 创建一个新的实例 CustomToast.
* @param context 上下文
* @param text 吐司内容
* @param time 显示时间LENGTH_LONG=1或者LENGTH_SHORT=0
*/
public static CustomToast show(Context context,String text,int time){
return new CustomToast(context,text,time);
}
/**
*
* 创建一个新的实例 CustomToast.
* @param context 上下文
* @param text 吐司内容
* @param time 显示时间LENGTH_LONG=1或者LENGTH_SHORT=0
*/
public CustomToast(Context context,String text,int time) {
super(context);
this.context = context;
this.text = text;
this.time = time;
init();
}
private void init() {
view = View.inflate(context, R.layout.custom_toast, null);
setView(view);
textView = (TextView) view.findViewById(R.id.textView);
textView.setText(text);
setGravity(Gravity.CENTER_HORIZONTAL, 0, 0);
setDuration(time);
show();
}
}
@@ -0,0 +1,84 @@
package cn.shangyu.gdxzExpert.widget;
import android.app.Dialog;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import cn.shangyu.gdxzExpert.R;
import cn.shangyu.gdxzExpert.R.style;
/**
*
* CustomerDialog.java
* @author ssy
* @date 2015-9-6 下午7:53:06
* Copyright (C) 2015 河南商宇科技有限公司
*
* 功能说明:重写弹窗,有标题有内容,有确定取消的按钮
*/
public class CustomerDialog extends Dialog{
private LayoutInflater layoutInflater;
private View view;
private TextView titleTv;
private TextView contentTv;
private Button okBtn;
private Button cancelBtn;
public CustomerDialog(Context context){
super(context, style.MyDialogStyle);//
// this.layoutInflater=LayoutInflater.from(context);
view=View.inflate(context, R.layout.update_dialog, null);
titleTv=(TextView) view.findViewById(R.id.tv_title);
contentTv=(TextView) view.findViewById(R.id.tv_message);
okBtn=(Button) view.findViewById(R.id.bt_dialog_ok);
cancelBtn=(Button) view.findViewById(R.id.bt_dialog_cancle);
setContentView(view);
}
@Override
public void setContentView(View view) {
super.setContentView(view);
}
public void setTitle(CharSequence title){
if (!TextUtils.isEmpty(title)) {
titleTv.setText(title);
}
}
public void setContent(CharSequence content){
contentTv.setText(content);
}
public void setOkBtnOnclickListener(View.OnClickListener listener){
okBtn.setOnClickListener(listener);
}
public void setCancelBtnOnclickListener(View.OnClickListener listener){
cancelBtn.setOnClickListener(listener);
}
@Override
public void dismiss() {
super.dismiss();
}
@Override
public void show() {
super.show();
}
}
@@ -0,0 +1,465 @@
/*
* Copyright (c) 2013 The CCP project authors. All Rights Reserved.
*
* Use of this source code is governed by a Beijing Speedtong Information Technology Co.,Ltd license
* that can be found in the LICENSE file in the root of the web site.
*
* http://www.yuntongxun.com
*
* An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package cn.shangyu.gdxzExpert.widget;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import com.gyf.immersionbar.ImmersionBar;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import cn.shangyu.gdxzExpert.R;
import cn.shangyu.gdxzExpert.utils.LogUtil;
/**
* 对话框
*
* @author Jorstin Chan@容联•云通讯
* @date 2015-1-3
* @version 4.0
*/
public class ECAlertDialog extends Dialog implements View.OnClickListener {
public static final String TAG = "ECDemo.ECAlertDialog";
/** 左边按钮 */
public static final int BUTTON_NEGATIVE = 0;
/** 中间按钮 */
public static final int BUTTON_NEUTRAL = 1;
/** 右边按钮 */
public static final int BUTTON_POSITIVE = 2;
private boolean mDismiss = true;
private boolean mCancelable = true;
private boolean mCanceledOnTouchOutside = false;
private List<Button> mButtons;
/** 对话框标题 */
private View mLayoutTitle;
/** 对话框内容 */
private ViewGroup mLayoutContent;
/** 对话框按钮 */
private View mLayoutButton;
/**
* @param context
*/
public ECAlertDialog(Context context) {
super(context, R.style.MyDialog);
super.setContentView(R.layout.common_dialog_generic);
initView(context);
}
/**
*
*/
private void initView(Context context) {
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
getWindow().setAttributes(layoutParams);
ImmersionBar.with((Activity) context, this)
// .statusBarDarkFont(true)
.keyboardEnable(true)
.init();
mButtons = new ArrayList<Button>();
Button leftBtn = (Button) findViewById(R.id.dilaog_button1);
leftBtn.setOnClickListener(this);
mButtons.add(leftBtn);
Button middleBtn = (Button) findViewById(R.id.dilaog_button2);
middleBtn.setOnClickListener(this);
mButtons.add(middleBtn);
Button rightBtn = (Button) findViewById(R.id.dilaog_button3);
rightBtn.setOnClickListener(this);
mButtons.add(rightBtn);
mLayoutTitle = findViewById(R.id.dialog_layout_title);
mLayoutContent = ((ViewGroup) findViewById(R.id.dialog_layout_content));
mLayoutButton = findViewById(R.id.dialog_layout_button);
setCancelable(true);
setCanceledOnTouchOutside(true);
setTitle(R.string.dialog_title_alert);
}
public static ECAlertDialog buildAlert(Context ctx, int message,
int button, OnClickListener listener) {
return buildAlert(ctx, ctx.getString(message), ctx.getString(button),
listener);
}
public static ECAlertDialog buildAlert(Context ctx, String message,
int button, OnClickListener listener) {
return buildAlert(ctx, message, ctx.getString(button), listener);
}
public static ECAlertDialog buildAlert(Context ctx, int resId,
OnClickListener listener) {
return buildAlert(ctx, resId, R.string.dialog_btn_cancel,
R.string.dialog_btn_confim, null, listener);
}
public static ECAlertDialog buildAlert(Context ctx, int resId,
OnClickListener negativeClickListener, OnClickListener positive) {
return buildAlert(ctx, ctx.getString(resId),
ctx.getString(R.string.dialog_btn_cancel),
ctx.getString(R.string.dialog_btn_confim),
negativeClickListener, positive);
}
public static ECAlertDialog buildAlert(Context ctx, CharSequence message,
OnClickListener listener) {
return buildAlert(ctx, message,
ctx.getString(R.string.dialog_btn_cancel),
ctx.getString(R.string.dialog_btn_confim), null, listener);
}
public static ECAlertDialog buildAlert(Context ctx, CharSequence message,
OnClickListener negativeClickListener, OnClickListener positive) {
return buildAlert(ctx, message,
ctx.getString(R.string.dialog_btn_cancel),
ctx.getString(R.string.dialog_btn_confim),
negativeClickListener, positive);
}
public static ECAlertDialog buildAlert(Context ctx, int message,
int leftBtnText, int rightText,
OnClickListener negativeClickListener, OnClickListener positive) {
return buildAlert(ctx, ctx.getString(message),
ctx.getString(leftBtnText), ctx.getString(rightText),
negativeClickListener, positive);
}
/**
* 创建对话框
*
* @param ctx
* 上下文
* @param message
* 对话框内容
* @param leftBtnText
* 取消按钮文本
* @param rightText
* 确定按钮文本
* @param negativeClickListener
* @param positive
* @return
*/
public static ECAlertDialog buildAlert(Context ctx, CharSequence message,
CharSequence leftBtnText, CharSequence rightText,
OnClickListener negativeClickListener, OnClickListener positive) {
ECAlertDialog dialog = new ECAlertDialog(ctx);
dialog.setMessage(message);
dialog.setButton(BUTTON_NEGATIVE, leftBtnText, negativeClickListener);
dialog.setButton(BUTTON_POSITIVE, rightText, positive);
return dialog;
}
/**
* 创建只有一个按钮的对话框
*
* @param ctx
* @param message
* @param text
* @param positive
* @return
*/
public static ECAlertDialog buildAlert(Context ctx, CharSequence message,
CharSequence text, OnClickListener positive) {
ECAlertDialog dialog = new ECAlertDialog(ctx);
dialog.setMessage(message);
dialog.setButton(BUTTON_NEGATIVE, text, positive);
return dialog;
}
public static ECAlertDialog buildPositiveAlert(Context ctx, int resId,
OnClickListener listener) {
return buildPositiveAlert(ctx, ctx.getString(resId), listener);
}
/**
*
* @param ctx
* @param message
* @param listener
* @return
*/
public static ECAlertDialog buildPositiveAlert(Context ctx,
CharSequence message, OnClickListener listener) {
ECAlertDialog dialog = new ECAlertDialog(ctx);
dialog.setMessage(message);
dialog.setButton(BUTTON_POSITIVE,
ctx.getString(R.string.dialog_btn_confim), listener);
return dialog;
}
/**
* 设置对话框按钮
*
* @param id
* @param resId
* @param listener
* @return
*/
public final Button setButton(int id, int resId, OnClickListener listener) {
return setButton(resId, getContext().getString(resId), listener);
}
/**
* 设置按钮
*
* @param id
* 按钮号
* @param text
* 按钮显示文本
* @param listener
* @return
*/
public final Button setButton(int id, CharSequence text,
OnClickListener listener) {
Button button = mButtons.get(id);
button.setText(text);
if (!TextUtils.isEmpty(text)) {
button.setVisibility(View.VISIBLE);
setButtonTag(id, listener);
mLayoutButton.setVisibility(View.VISIBLE);
}
return button;
}
public final ECAlertDialog setButtonTag(int id, OnClickListener listener) {
Button button = mButtons.get(id);
button.setTag(listener);
return this;
}
public final void setMessage(int resId) {
setMessage(getContext().getString(resId));
}
/**
* 设置对话框显示文本
*
* @param text
*/
public final void setMessage(CharSequence text) {
((TextView) findViewById(R.id.dialog_tv_message)).setText(text);
}
public final void setMessageColor(String textColor) {
((TextView) findViewById(R.id.dialog_tv_message)).setTextColor(Color.parseColor(textColor));
((TextView) findViewById(R.id.dialog_tv_message)).setEllipsize(TextUtils.TruncateAt.END);
((TextView) findViewById(R.id.dialog_tv_message)).setLines(2);
}
public final void setTitleNormalColor() {
((TextView) findViewById(R.id.dialog_tv_title))
.setTextColor(getContext().getResources().getColor(
R.color.text_content));
}
/**
* 设置标题是否可见
*
* @param visibility
*/
public final void setTitleVisibility(int visibility) {
mLayoutTitle.setVisibility(visibility);
}
/**
* 设置内容显示区域
*
* @param left
* @param top
* @param right
* @param bottom
*/
public final void setContentPadding(int left, int top, int right, int bottom) {
if (left < 0) {
left = mLayoutContent.getPaddingLeft();
}
if (top < 0) {
top = mLayoutContent.getPaddingRight();
}
if (right < 0) {
right = mLayoutContent.getPaddingTop();
}
if (bottom < 0) {
bottom = mLayoutContent.getPaddingBottom();
}
Drawable localDrawable = mLayoutContent.getBackground();
mLayoutContent.setPadding(left, top, right, bottom);
mLayoutContent.setBackgroundDrawable(localDrawable);
}
public final View getContent() {
return mLayoutContent;
}
/**
* 点击按钮不销毁对话框
*/
public void setDismissFalse() {
mDismiss = false;
}
/**
*
* @param view
* @return
*/
private int getViewLocation(View view) {
for (int i = 0; i < mButtons.size(); i++) {
if (mButtons.get(i) == view) {
return i;
}
}
return -1;
}
@Override
public void onClick(View v) {
OnClickListener clickListener = (OnClickListener) v.getTag();
if (clickListener != null) {
clickListener.onClick(this, getViewLocation(v));
}
if (mDismiss) {
dismiss();
return;
}
// mDismiss = true;
}
public void setCancelable(boolean flag) {
super.setCancelable(flag);
mCancelable = flag;
}
public void setCanceledOnTouchOutside(boolean cancel) {
super.setCanceledOnTouchOutside(cancel);
mCanceledOnTouchOutside = cancel;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
LogUtil.d(TAG, "onTouchEvent");
if (mCancelable && mCanceledOnTouchOutside
&& event.getAction() == MotionEvent.ACTION_DOWN) {
cancel();
return true;
}
return super.onTouchEvent(event);
}
/**
* 设置自定义View
*/
public final void setContentView(int resource) {
setContentView(getLayoutInflater().inflate(resource, null));
}
public void setContentView(View contentView) {
if (mLayoutContent.getChildCount() > 0) {
mLayoutContent.removeAllViews();
}
mLayoutContent.addView(contentView);
}
public void setContentView(View child, ViewGroup.LayoutParams params) {
if (mLayoutContent.getChildCount() > 0) {
mLayoutContent.removeAllViews();
}
mLayoutContent.addView(child, params);
}
/**
* 设置对话框标题
*/
public void setTitle(int title) {
setTitle(getContext().getString(title));
}
/**
* 设置对话框标题
*/
public void setTitle(CharSequence text) {
if ((text == null) || (TextUtils.isEmpty(text.toString()))) {
mLayoutContent.setVisibility(View.VISIBLE);
setTitleVisibility(View.GONE);
return;
}
((TextView) findViewById(R.id.dialog_tv_title)).setText(text);
mLayoutContent.setVisibility(View.VISIBLE);
setTitleVisibility(View.VISIBLE);
}
/**
* 设置对话框标题字体颜色
*/
public void setTitleColor(int color) {
((TextView) findViewById(R.id.dialog_tv_title)).setTextColor(color);
mLayoutContent.setVisibility(View.VISIBLE);
setTitleVisibility(View.VISIBLE);
}
public void show() {
super.show();
int i = 0;
Button btn = null;
Iterator<Button> iterator = mButtons.iterator();
while (iterator.hasNext()) {
Button button = iterator.next();
if (button.getVisibility() != View.VISIBLE) {
continue;
}
++i;
btn = button;
}
if (i == 1) {
btn.setBackgroundResource(R.drawable.btn_dialog_single);
}
if (i == 2) {
btn.setSelected(true);
((ViewGroup.MarginLayoutParams) (this.mButtons.get(0))
.getLayoutParams()).rightMargin = 1;
}
if (i == 3) {
btn.setSelected(true);
((ViewGroup.MarginLayoutParams) (this.mButtons.get(2))
.getLayoutParams()).leftMargin = 1;
((ViewGroup.MarginLayoutParams) (this.mButtons.get(0))
.getLayoutParams()).rightMargin = 1;
}
}
@Override
public void dismiss() {
View view = getCurrentFocus();
if(view instanceof TextView){
InputMethodManager mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
mInputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);
}
super.dismiss();
}
}
@@ -0,0 +1,124 @@
package cn.shangyu.gdxzExpert.widget;
import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Arrays;
import java.util.List;
import cn.shangyu.gdxzExpert.R;
import cn.shangyu.gdxzExpert.ecdemo.view.IBaseAdapter;
/**
* com.yuntongxun.ecdemo.common.dialog in ECDemo_Android
* Created by Jorstin on 2015/4/18.
*/
public class ECListDialog extends ECAlertDialog implements AdapterView.OnItemClickListener {
private int mCheckIndex;
private ListView mListView;
private OnDialogItemClickListener mListener;
/**
* @param context
*/
public ECListDialog(Context context) {
super(context);
mCheckIndex = -1;
mListener = null;
mListView = null;
// setTitleNormalColor();
View contatinView = LayoutInflater.from(context).inflate(R.layout.include_dialog_simplelist ,null);
setContentView(contatinView);
setContentPadding(0,0,0,-1);
mListView = (ListView) contatinView.findViewById(R.id.listview);
mListView.setOnItemClickListener(this);
}
/**
*据数组资源文件创建\\
* @param context
* @param resourceIdArray
*/
public ECListDialog(Context context , int resourceIdArray) {
this(context);
String[] stringArray = context.getResources().getStringArray(resourceIdArray);
setAdapter(new ListDialogAdapter(getContext(), Arrays.asList(stringArray)));
}
/**
* 根据集合数组创建
* @param context
* @param strs
*/
public ECListDialog(Context context , List<String> strs) {
this(context);
setAdapter(new ListDialogAdapter(getContext(), strs));
}
public ECListDialog(Context context , List<String> strs , int checkPosition) {
this(context ,strs);
this.mCheckIndex = checkPosition;
}
public ECListDialog(Context context , String[] strs , int checkPosition) {
this(context ,strs);
this.mCheckIndex = checkPosition;
}
public ECListDialog(Context context , String[] strs) {
this(context);
setAdapter(new ListDialogAdapter(getContext(), Arrays.asList(strs)));
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(mListener != null) {
mListener.onDialogItemClick(this , position);
}
dismiss();
}
public void setAdapter(ListAdapter adapter) {
mListView.setAdapter(adapter);
}
public class ListDialogAdapter extends IBaseAdapter<String> {
public ListDialogAdapter(Context ctx, List<String> data) {
super(ctx, data);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = this.mLayoutInflater.inflate(R.layout.listitem_dialog , null);
}
((TextView) convertView.findViewById(R.id.textview)).setText(getItem(position).toString());
if(mCheckIndex == position) {
convertView.findViewById(R.id.imageview).setVisibility(View.VISIBLE);
} else {
convertView.findViewById(R.id.imageview).setVisibility(View.GONE);
}
return convertView;
}
}
public void setOnDialogItemClickListener(OnDialogItemClickListener l) {
this.mListener = l;
}
public interface OnDialogItemClickListener {
void onDialogItemClick(Dialog d, int position);
}
}
@@ -0,0 +1,106 @@
/*
* Copyright (c) 2013 The CCP project authors. All Rights Reserved.
*
* Use of this source code is governed by a Beijing Speedtong Information Technology Co.,Ltd license
* that can be found in the LICENSE file in the root of the web site.
*
* http://www.yuntongxun.com
*
* An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package cn.shangyu.gdxzExpert.widget;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.TextView;
import cn.shangyu.gdxzExpert.R;
/**
* 网络访问对话框
* @author Jorstin Chan@容联•云通讯
* @date 2015-1-4
* @version 4.0
*/
public class ECProgressDialog extends Dialog {
private TextView mTextView;
private View mImageView;
AsyncTask mAsyncTask;
private final OnCancelListener mCancelListener
= new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
if(mAsyncTask != null) {
mAsyncTask.cancel(true);
}
}
};
/**
* @param context
*/
public ECProgressDialog(Context context) {
super(context , R.style.Theme_Light_CustomDialog_Blue);
mAsyncTask = null;
setCancelable(true);
setContentView(R.layout.common_loading_diloag);
mTextView = (TextView)findViewById(R.id.textview);
mTextView.setText(R.string.loading_press);
mImageView = findViewById(R.id.imageview);
setOnCancelListener(mCancelListener);
}
/**
* @param context
* @param resid
*/
public ECProgressDialog(Context context , int resid) {
this(context);
mTextView.setText(resid);
}
public ECProgressDialog(Context context , CharSequence text) {
this(context);
mTextView.setText(text);
}
public ECProgressDialog(Context context , AsyncTask asyncTask) {
this(context);
mAsyncTask = asyncTask;
}
public ECProgressDialog(Context context , CharSequence text , AsyncTask asyncTask) {
this(context , text);
mAsyncTask = asyncTask;
}
/**
* 设置对话框显示文本
* @param text
*/
public final void setPressText(CharSequence text) {
mTextView.setText(text);
}
public final void dismiss() {
super.dismiss();
mImageView.clearAnimation();
}
public final void show() {
super.show();
Animation loadAnimation = AnimationUtils.loadAnimation(getContext() , R.anim.loading);
mImageView.startAnimation(loadAnimation);
}
}
@@ -0,0 +1,528 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Build;
import android.text.Layout;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.AlignmentSpan;
import android.text.style.ClickableSpan;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import java.lang.reflect.Field;
public class ExpandTextView extends AppCompatTextView {
public static final String ELLIPSIS_STRING = new String(new char[]{'\u2026'});
private static final int DEFAULT_MAX_LINE = 2;
private static final String DEFAULT_OPEN_SUFFIX = " 展开全部";
private static final String DEFAULT_CLOSE_SUFFIX = " 收起";
volatile boolean animating = false;
boolean isClosed = false;
private int mMaxLines = DEFAULT_MAX_LINE;
/** TextView可展示宽度,包含paddingLeft和paddingRight */
private int initWidth = 0;
/** 原始文本 */
private CharSequence originalText;
private SpannableStringBuilder mOpenSpannableStr, mCloseSpannableStr;
private boolean hasAnimation = false;
private Animation mOpenAnim, mCloseAnim;
private int mOpenHeight, mCLoseHeight;
private boolean mExpandable;
private boolean mCloseInNewLine;
@Nullable
private SpannableString mOpenSuffixSpan, mCloseSuffixSpan;
private String mOpenSuffixStr = DEFAULT_OPEN_SUFFIX;
private String mCloseSuffixStr = DEFAULT_CLOSE_SUFFIX;
private int mOpenSuffixColor, mCloseSuffixColor;
private View.OnClickListener mOnClickListener;
private CharSequenceToSpannableHandler mCharSequenceToSpannableHandler;
public ExpandTextView(Context context) {
this(context,null);
}
public ExpandTextView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ExpandTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
/** 初始化 */
private void initialize() {
mOpenSuffixColor = mCloseSuffixColor = Color.parseColor("#8B2316");
setMovementMethod(OverLinkMovementMethod.getInstance());
setIncludeFontPadding(false);
updateOpenSuffixSpan();
updateCloseSuffixSpan();
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
public void setOriginalText(CharSequence originalText) {
this.originalText = originalText;
mExpandable = false;
mCloseSpannableStr = new SpannableStringBuilder();
final int maxLines = mMaxLines;
SpannableStringBuilder tempText = charSequenceToSpannable(originalText);
mOpenSpannableStr = charSequenceToSpannable(originalText);
if (maxLines != -1) {
Layout layout = createStaticLayout(tempText);
mExpandable = layout.getLineCount() > maxLines;
if (mExpandable) {
//拼接展开内容
if (mCloseInNewLine) {
mOpenSpannableStr.append("\n");
}
if (mCloseSuffixSpan != null) {
mOpenSpannableStr.append(mCloseSuffixSpan);
}
//计算原文截取位置
int endPos = layout.getLineEnd(maxLines - 1);
if (originalText.length() <= endPos) {
mCloseSpannableStr = charSequenceToSpannable(originalText);
} else {
mCloseSpannableStr = charSequenceToSpannable(originalText.subSequence(0, endPos));
}
SpannableStringBuilder tempText2 = charSequenceToSpannable(mCloseSpannableStr).append(ELLIPSIS_STRING);
if (mOpenSuffixSpan != null) {
tempText2.append(mOpenSuffixSpan);
}
//循环判断,收起内容添加展开后缀后的内容
Layout tempLayout = createStaticLayout(tempText2);
while (tempLayout.getLineCount() > maxLines) {
int lastSpace = mCloseSpannableStr.length() - 1;
if (lastSpace == -1) {
break;
}
if (originalText.length() <= lastSpace) {
mCloseSpannableStr = charSequenceToSpannable(originalText);
} else {
mCloseSpannableStr = charSequenceToSpannable(originalText.subSequence(0, lastSpace));
}
tempText2 = charSequenceToSpannable(mCloseSpannableStr).append(ELLIPSIS_STRING);
if (mOpenSuffixSpan != null) {
tempText2.append(mOpenSuffixSpan);
}
tempLayout = createStaticLayout(tempText2);
}
// int lastSpace = mCloseSpannableStr.length() - mOpenSuffixSpan.length();
int lastSpace = mCloseSpannableStr.length() - 1;
if(lastSpace >= 0 && originalText.length() > lastSpace){
CharSequence redundantChar = originalText.subSequence(lastSpace, lastSpace + mOpenSuffixSpan.length());
int offset = hasEnCharCount(redundantChar) - hasEnCharCount(mOpenSuffixSpan) + 1;
lastSpace = offset <= 0 ? lastSpace : lastSpace - offset;
mCloseSpannableStr = charSequenceToSpannable(originalText.subSequence(0, lastSpace));
}
//计算收起的文本高度
mCLoseHeight = tempLayout.getHeight() + getPaddingTop() + getPaddingBottom();
mCloseSpannableStr.append(ELLIPSIS_STRING);
if (mOpenSuffixSpan != null) {
mCloseSpannableStr.append(mOpenSuffixSpan);
}
}
}
isClosed = mExpandable;
if (mExpandable) {
setText(mCloseSpannableStr);
//设置监听
super.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// switchOpenClose();
// if (mOnClickListener != null) {
// mOnClickListener.onClick(v);
// }
}
});
} else {
setText(mOpenSpannableStr);
}
}
private int hasEnCharCount(CharSequence str){
int count = 0;
if(!TextUtils.isEmpty(str)){
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(c >= ' ' && c <= '~'){
count++;
}
}
}
return count;
}
private void switchOpenClose() {
if (mExpandable) {
isClosed = !isClosed;
if (isClosed) {
close();
} else {
open();
}
}
}
/**
* 设置是否有动画
*
* @param hasAnimation
*/
public void setHasAnimation(boolean hasAnimation) {
this.hasAnimation = hasAnimation;
}
/** 展开 */
private void open() {
if (hasAnimation) {
Layout layout = createStaticLayout(mOpenSpannableStr);
mOpenHeight = layout.getHeight() + getPaddingTop() + getPaddingBottom();
executeOpenAnim();
} else {
ExpandTextView.super.setMaxLines(Integer.MAX_VALUE);
setText(mOpenSpannableStr);
if (mOpenCloseCallback != null){
mOpenCloseCallback.onOpen();
}
}
}
/** 收起 */
private void close() {
if (hasAnimation) {
executeCloseAnim();
} else {
ExpandTextView.super.setMaxLines(mMaxLines);
setText(mCloseSpannableStr);
if (mOpenCloseCallback != null){
mOpenCloseCallback.onClose();
}
}
}
/** 执行展开动画 */
private void executeOpenAnim() {
//创建展开动画
if (mOpenAnim == null) {
mOpenAnim = new ExpandCollapseAnimation(this, mCLoseHeight, mOpenHeight);
mOpenAnim.setFillAfter(true);
mOpenAnim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
ExpandTextView.super.setMaxLines(Integer.MAX_VALUE);
setText(mOpenSpannableStr);
}
@Override
public void onAnimationEnd(Animation animation) {
// 动画结束后textview设置展开的状态
getLayoutParams().height = mOpenHeight;
requestLayout();
animating = false;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
if (animating) {
return;
}
animating = true;
clearAnimation();
// 执行动画
startAnimation(mOpenAnim);
}
/** 执行收起动画 */
private void executeCloseAnim() {
//创建收起动画
if (mCloseAnim == null) {
mCloseAnim = new ExpandCollapseAnimation(this, mOpenHeight, mCLoseHeight);
mCloseAnim.setFillAfter(true);
mCloseAnim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
animating = false;
ExpandTextView.super.setMaxLines(mMaxLines);
setText(mCloseSpannableStr);
getLayoutParams().height = mCLoseHeight;
requestLayout();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
if (animating) {
return;
}
animating = true;
clearAnimation();
// 执行动画
startAnimation(mCloseAnim);
}
/**
* @param spannable
*
* @return
*/
private Layout createStaticLayout(SpannableStringBuilder spannable) {
int contentWidth = initWidth - getPaddingLeft() - getPaddingRight();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
StaticLayout.Builder builder = StaticLayout.Builder.obtain(spannable, 0, spannable.length(), getPaint(), contentWidth);
builder.setAlignment(Layout.Alignment.ALIGN_NORMAL);
builder.setIncludePad(getIncludeFontPadding());
builder.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier());
return builder.build();
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return new StaticLayout(spannable, getPaint(), contentWidth, Layout.Alignment.ALIGN_NORMAL,
getLineSpacingMultiplier(), getLineSpacingExtra(), getIncludeFontPadding());
}else{
return new StaticLayout(spannable, getPaint(), contentWidth, Layout.Alignment.ALIGN_NORMAL,
getFloatField("mSpacingMult",1f), getFloatField("mSpacingAdd",0f), getIncludeFontPadding());
}
}
private float getFloatField(String fieldName,float defaultValue){
float value = defaultValue;
if(TextUtils.isEmpty(fieldName)){
return value;
}
try {
// 获取该类的所有属性值域
Field[] fields = this.getClass().getDeclaredFields();
for (Field field:fields) {
if(TextUtils.equals(fieldName,field.getName())){
value = field.getFloat(this);
break;
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return value;
}
/**
* @param charSequence
*
* @return
*/
private SpannableStringBuilder charSequenceToSpannable(@NonNull CharSequence charSequence) {
SpannableStringBuilder spannableStringBuilder = null;
if (mCharSequenceToSpannableHandler != null) {
spannableStringBuilder = mCharSequenceToSpannableHandler.charSequenceToSpannable(charSequence);
}
if (spannableStringBuilder == null) {
spannableStringBuilder = new SpannableStringBuilder(charSequence);
}
return spannableStringBuilder;
}
/**
* 初始化TextView的可展示宽度
*
* @param width
*/
public void initWidth(int width) {
initWidth = width;
}
@Override
public void setMaxLines(int maxLines) {
this.mMaxLines = maxLines;
super.setMaxLines(maxLines);
}
/**
* 设置展开后缀text
*
* @param openSuffix
*/
public void setOpenSuffix(String openSuffix) {
mOpenSuffixStr = openSuffix;
updateOpenSuffixSpan();
}
/**
* 设置展开后缀文本颜色
*
* @param openSuffixColor
*/
public void setOpenSuffixColor(@ColorInt int openSuffixColor) {
mOpenSuffixColor = openSuffixColor;
updateOpenSuffixSpan();
}
/**
* 设置收起后缀text
*
* @param closeSuffix
*/
public void setCloseSuffix(String closeSuffix) {
mCloseSuffixStr = closeSuffix;
updateCloseSuffixSpan();
}
/**
* 设置收起后缀文本颜色
*
* @param closeSuffixColor
*/
public void setCloseSuffixColor(@ColorInt int closeSuffixColor) {
mCloseSuffixColor = closeSuffixColor;
updateCloseSuffixSpan();
}
/**
* 收起后缀是否另起一行
*
* @param closeInNewLine
*/
public void setCloseInNewLine(boolean closeInNewLine) {
mCloseInNewLine = closeInNewLine;
updateCloseSuffixSpan();
}
/** 更新展开后缀Spannable */
private void updateOpenSuffixSpan() {
if (TextUtils.isEmpty(mOpenSuffixStr)) {
mOpenSuffixSpan = null;
return;
}
mOpenSuffixSpan = new SpannableString(mOpenSuffixStr);
mOpenSuffixSpan.setSpan(new StyleSpan(Typeface.NORMAL), 0, mOpenSuffixStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mOpenSuffixSpan.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
switchOpenClose();
}
@Override
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(mOpenSuffixColor);
ds.setUnderlineText(false);
}
},0, mOpenSuffixStr.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
}
/** 更新收起后缀Spannable */
private void updateCloseSuffixSpan() {
if (TextUtils.isEmpty(mCloseSuffixStr)) {
mCloseSuffixSpan = null;
return;
}
mCloseSuffixSpan = new SpannableString(mCloseSuffixStr);
mCloseSuffixSpan.setSpan(new StyleSpan(Typeface.NORMAL), 0, mCloseSuffixStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (mCloseInNewLine) {
AlignmentSpan alignmentSpan = new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE);
mCloseSuffixSpan.setSpan(alignmentSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
mCloseSuffixSpan.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
switchOpenClose();
}
@Override
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(mCloseSuffixColor);
ds.setUnderlineText(false);
}
},1, mCloseSuffixStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
@Override
public void setOnClickListener(View.OnClickListener onClickListener) {
mOnClickListener = onClickListener;
}
public OpenAndCloseCallback mOpenCloseCallback;
public void setOpenAndCloseCallback(OpenAndCloseCallback callback){
this.mOpenCloseCallback = callback;
}
public interface OpenAndCloseCallback{
void onOpen();
void onClose();
}
/**
* 设置文本内容处理
*
* @param handler
*/
public void setCharSequenceToSpannableHandler(CharSequenceToSpannableHandler handler) {
mCharSequenceToSpannableHandler = handler;
}
public interface CharSequenceToSpannableHandler {
@NonNull
SpannableStringBuilder charSequenceToSpannable(CharSequence charSequence);
}
class ExpandCollapseAnimation extends Animation {
private final View mTargetView;//动画执行view
private final int mStartHeight;//动画执行的开始高度
private final int mEndHeight;//动画结束后的高度
ExpandCollapseAnimation(View target, int startHeight, int endHeight) {
mTargetView = target;
mStartHeight = startHeight;
mEndHeight = endHeight;
setDuration(400);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mTargetView.setScrollY(0);
//计算出每次应该显示的高度,改变执行view的高度,实现动画
mTargetView.getLayoutParams().height = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
mTargetView.requestLayout();
}
}
}
@@ -0,0 +1,71 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RadioGroup;
public class GridRadioGroup extends RadioGroup {
//子布局RadioButton 列数
private int column = 2;
//文字
private int textPaddingTB = 0;
private int widthmargin = 0;
private int heighmargin = 0;
private int itemWidth;
public GridRadioGroup(Context context) {
this(context, null);
}
public GridRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
itemWidth = (widthSize - (column + 1) * widthmargin) / column;
int childCount = getChildCount();
int itemHeight = 0;
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
child.setPadding(0, textPaddingTB, 0, textPaddingTB);
child.measure(MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY),
MeasureSpec.UNSPECIFIED);
itemHeight = child.getMeasuredHeight();
}
int rows = childCount % column == 0 ? childCount / column : childCount / column + 1;
int heightSize = rows * itemHeight + (rows + 1) * heighmargin;
setMeasuredDimension(widthMeasureSpec, heightSize);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int rows = 0;
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
int yu = i % column;
int cl, ct, cr, cb;
if (i >= column - 1 && yu == 0) {
rows++;
}
cl = widthmargin * (yu + 1) + yu * width;
ct = heighmargin * (rows + 1) + rows * height;
cr = widthmargin * (yu + 1) + (yu + 1) * width;
cb = heighmargin * (rows + 1) + (rows + 1) * height;
view.layout(cl, ct, cr, cb);
}
}
}
@@ -0,0 +1,197 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import cn.shangyu.gdxzExpert.R;
import cn.shangyu.gdxzExpert.manager.ThreadManager;
import cn.shangyu.gdxzExpert.utils.UIUtils;
/**
*
* LoadingPage.java
* @author ssy
* @date 2015-8-31 上午10:26:17
* Copyright (C) 2015 河南商宇科技有限公司
*
* 功能说明:加载网络显示的页面
*/
public abstract class LoadingPage extends FrameLayout {
// 未加载
private int STATE_UNLOAD = 0;
// 正在加载
private int STATE_LOADING = 1;
// 加载错误
private int STATE_ERROR = 2;
// 加载为空
private int STATE_EMPTY = 3;
// 加载成功
private int STATE_SUCCESSED = 4;
private int state;
// 正在加载对应的view对象
private View loadingView;
protected View errorView;
private View emptyView;
private View successedView;
private LayoutParams layoutParams;
/**
* 在代码中,用findViewById方法 ,通过ID获得对象实例时,由系统自动调用
*
* @param context
* @param attrs
*/
public LoadingPage(Context context, AttributeSet attrs) {
super(context, attrs);
layoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
initView();
}
public LoadingPage(Context context) {
super(context);
layoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
initView();
}
private void initView() {
// 先将多个状态对应的界面效果添加到帧布局中
state = STATE_UNLOAD;
if (loadingView == null) {
loadingView = UIUtils.inflate(R.layout.layout_loading);
// 添加到FragmentLayout
addView(loadingView, layoutParams);
}
if (errorView == null) {
errorView = UIUtils.inflate(R.layout.layout_error);
// 添加到FragmentLayout
addView(errorView, layoutParams);
}
if (emptyView == null) {
emptyView = UIUtils.inflate(R.layout.layout_empty);
// 添加到FragmentLayout
addView(emptyView, layoutParams);
}
// 安全显示UI的操作
showSafePage();
}
private void showSafePage() {
UIUtils.runInMainThread(new Runnable() {
@Override
public void run() {
showPage();
}
});
}
private void showPage() {
// 在默认状态下展示lodingView
if (loadingView != null) {
// 状态判断当前view的显示隐藏
loadingView
.setVisibility((state == STATE_UNLOAD || state == STATE_LOADING) ? View.VISIBLE
: View.GONE);
}
// 错误界面的展示
if (errorView != null) {
errorView.setVisibility((state == STATE_ERROR) ? View.VISIBLE
: View.GONE);
}
// 为空界面的展示
if (emptyView != null) {
emptyView.setVisibility((state == STATE_EMPTY) ? View.VISIBLE
: View.GONE);
}
// 成功加载的界面
if (successedView == null && state == STATE_SUCCESSED) {
successedView = onCreateSuccessedView();
addView(successedView, layoutParams);
}
// 根据状态判断是否显示
if (successedView != null) {
successedView
.setVisibility((state == STATE_SUCCESSED) ? View.VISIBLE
: View.GONE);
}
}
class RunnableTask implements Runnable {
@Override
public void run() {
// 请求网络操作
final ResultState onLoad = onLoad();
UIUtils.runInMainThread(new Runnable() {
@Override
public void run() {
if (onLoad != null) {
state = onLoad.getValue();
// 根据请求网络的状态,做页面的选择展示
showPage();
}
}
});
}
}
public void show() {
if (state == STATE_EMPTY || state == STATE_ERROR
|| state == STATE_SUCCESSED) {
state = STATE_UNLOAD;
}
// 准备做请求网络操作
if (state == STATE_UNLOAD) {
ThreadManager.getThreadProxyPool().execute(new RunnableTask());
}
}
// 创建成功界面的方法,具体实现未知
public abstract View onCreateSuccessedView();
// 失败,为空,成功
public abstract ResultState onLoad();
// 枚举决定返回值类型
public enum ResultState {
STATE_LOADING(1), STATE_ERROR(2), STATE_EMPTY(3), STATE_SUCCESSED(4);
private int value;
private ResultState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
// 切换view
public void changeView(View view) {
if (view != null) {
removeView(successedView);
successedView = view;
addView(view);
showSafePage();
}
}
}
@@ -0,0 +1,233 @@
package cn.shangyu.gdxzExpert.widget;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import cn.shangyu.gdxzExpert.R;
/**
*
* 类名称:MyAlertDialog
* 类描述:自定义对话框,包含进度条的对话框,也可以填充自定义布局的对话框,为空则设置默认自定义的对话框
* 创建人:苏三元
* 时间:2015-9-7 上午10:50:10
* 版权:河南商宇科技有限公司--版权所有 (c) 2015
*
*/
public class MyAlertDialog implements OnClickListener{
private Context context;
private ProgressBar pb_update;
private TextView tv_message;
private Button bt_cancle;
private AlertDialog d;
private TextView tv_title;
private Button bt_ok;
private View view = null;
private Builder builder;
private Button bt_singlebutton;
public MyAlertDialog(Context context) {
super();
this.context = context;
init();
}
public TextView getTv_title() {
return tv_title;
}
public Button getBt_singlebutton() {
return bt_singlebutton;
}
public Button getBt_ok() {
return bt_ok;
}
public Context getContext() {
return context;
}
public ProgressBar getPb_update() {
return pb_update;
}
public TextView getTv_message() {
return tv_message;
}
public Button getBt_cancle() {
return bt_cancle;
}
public AlertDialog getD() {
return d;
}
public View getView() {
return view;
}
/**
* 设置对话框布局,如果设置了,只有对话框的方法可使用,控件的方法勿使用,为空则设置默认自定义的对话框
*/
public void setView(View view) {
this.view = view;
}
private void init() {
builder = new Builder(getContext(), R.style.CustomDialogStyle);
if(getView() == null){
view = View.inflate(getContext(), R.layout.update_dialog, null);
tv_title = (TextView) view.findViewById(R.id.tv_title);
pb_update = (ProgressBar) view.findViewById(R.id.pb_update);
tv_message = (TextView) view.findViewById(R.id.tv_message);
bt_singlebutton = (Button) view.findViewById(R.id.bt_cancle_update);
bt_ok = (Button) view.findViewById(R.id.bt_dialog_ok);
bt_cancle = (Button) view.findViewById(R.id.bt_dialog_cancle);
bt_singlebutton.setOnClickListener(this);
bt_ok.setOnClickListener(this);
bt_cancle.setOnClickListener(this);
}
}
/**
* 设置单个按钮是否显示状态,默认不显示
*/
public void setSingleButton(int visibility ){
bt_singlebutton.setVisibility(visibility);
}
/**
* 设置对话框单个按钮,设置监听器后要设置对话框dismiss
*/
public void setSingleButton(String text, final OnClickListener listener){
if(text != null || text != ""){
bt_singlebutton.setText(text);
}
if(listener != null){
bt_singlebutton.setOnClickListener(listener);
}
}
/**
* 设置对话框确定按钮
*/
public void setPositiveButton(String text, final OnClickListener listener){
if(text != null || text != ""){
bt_ok.setText(text);
}
if(listener != null){
bt_ok.setOnClickListener(listener);
}
}
/**
* 设置对话框取消按钮
*/
public void setNegativeButton(String text, final OnClickListener listener){
if(text != null || text != ""){
bt_cancle.setText(text);
}
if(listener != null){
bt_cancle.setOnClickListener(listener);
}
}
/**
* 设置升级进度条是否显示状态,默认gone
*/
public void setProgressBarVisibility(int visibility ){
pb_update.setVisibility(visibility);
}
/**
* 设置升级进度条的进度
*/
public void setProgress(int p ){
pb_update.setProgress(p);
}
/**
* 设置信息是否显示状态,默认显示
*/
public void setMessageVisibility(int visibility ){
tv_message.setVisibility(visibility);
}
/**
* 设置信息
*/
public void setMessage(String mes){
tv_message.setText(mes);
}
/**
* 设置对话框标题是否显示状态,默认显示
*/
public void setTitleVisibility(int visibility ){
tv_title.setVisibility(visibility);
}
/**
* 设置对话框标题
*/
public void setTitle(String title ){
tv_title.setText(title);
}
/**
* 设置对话框是否消失
*/
public void dismiss(){
d.dismiss();
}
/**
* 设置对话框填充的布局View
*/
public void setDialogView(View view){
d.setView(view, 0, 0, 0, 0);
}
/**
* 设置返回键不可以取消对话框,默认为TRUE
*/
public void setCancelable(Boolean b){
builder.setCancelable(b);
}
/**
* 设置对话框创建显示
*/
public void show(){
d = builder.create();
setDialogView(view);
d.show();
}
@Override
public void onClick(View v) {
dismiss();
}
// final Dialog dialog = new Dialog(SplashActivity.this, R.style.dialog);
// dialog.setCancelable(false);
// // 设置普通对话框的布局
// dialog.setContentView(R.layout.update_dialog);
// pb_update = (ProgressBar) dialog.findViewById(R.id.pb_update);
// tv_update = (TextView) dialog.findViewById(R.id.tv_update);
//// tv_jindu = (TextView) dialog.findViewById(R.id.tv_jindu);
// bt_cancle = (Button) dialog.findViewById(R.id.bt_cancle_update);
// bt_cancle.setOnClickListener(new View.OnClickListener() {
//
// @Override
// public void onClick(View v) {
// hh.stop();
// dialog.dismiss();
// enterHome();
// }
// });
// dialog.show();
}
@@ -0,0 +1,148 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.webkit.WebView;
import androidx.core.view.MotionEventCompat;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.ViewCompat;
public class NestedScrollWebView extends WebView implements NestedScrollingChild {
public static final String TAG = NestedScrollWebView.class.getSimpleName();
private int mLastMotionY;
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
private int mNestedYOffset;
private NestedScrollingChildHelper mChildHelper;
public NestedScrollWebView(Context context) {
super(context);
init();
}
public NestedScrollWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public NestedScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = false;
MotionEvent trackedEvent = MotionEvent.obtain(event);
final int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_DOWN) {
mNestedYOffset = 0;
}
int y = (int) event.getY();
event.offsetLocation(0, mNestedYOffset);
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
result = super.onTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
int deltaY = mLastMotionY - y;
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
deltaY -= mScrollConsumed[1];
trackedEvent.offsetLocation(0, mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
}
int oldY = getScrollY();
mLastMotionY = y - mScrollOffset[1];
int newScrollY = Math.max(0, oldY + deltaY);
deltaY -= newScrollY - oldY;
if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
mLastMotionY -= mScrollOffset[1];
trackedEvent.offsetLocation(0, mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
}
if(mScrollConsumed[1]==0 && mScrollOffset[1]==0) {
trackedEvent.recycle();
result = super.onTouchEvent(trackedEvent);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stopNestedScroll();
result = super.onTouchEvent(event);
break;
}
return result;
}
// NestedScrollingChild
@Override
public void setNestedScrollingEnabled(boolean enabled) {
mChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean isNestedScrollingEnabled() {
return mChildHelper.isNestedScrollingEnabled();
}
@Override
public boolean startNestedScroll(int axes) {
return mChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
}
@@ -0,0 +1,124 @@
package cn.shangyu.gdxzExpert.widget;
import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Arrays;
import java.util.List;
import cn.shangyu.gdxzExpert.R;
import cn.shangyu.gdxzExpert.ecdemo.view.IBaseAdapter;
/**
* com.yuntongxun.ecdemo.common.dialog in ECDemo_Android
* Created by Jorstin on 2015/4/18.
*/
public class NewECListDialog extends ECAlertDialog implements AdapterView.OnItemClickListener {
private int mCheckIndex;
private ListView mListView;
private OnDialogItemClickListener mListener;
/**
* @param context
*/
public NewECListDialog(Context context) {
super(context);
mCheckIndex = -1;
mListener = null;
mListView = null;
// setTitleNormalColor();
View contatinView = LayoutInflater.from(context).inflate(R.layout.include_dialog_simplelist ,null);
setContentView(contatinView);
setContentPadding(0,0,0,-1);
mListView = (ListView) contatinView.findViewById(R.id.listview);
mListView.setOnItemClickListener(this);
}
/**
*据数组资源文件创建\\
* @param context
* @param resourceIdArray
*/
public NewECListDialog(Context context , int resourceIdArray) {
this(context);
String[] stringArray = context.getResources().getStringArray(resourceIdArray);
setAdapter(new ListDialogAdapter(getContext(), Arrays.asList(stringArray)));
}
/**
* 根据集合数组创建
* @param context
* @param strs
*/
public NewECListDialog(Context context , List<String> strs) {
this(context);
setAdapter(new ListDialogAdapter(getContext(), strs));
}
public NewECListDialog(Context context , List<String> strs , int checkPosition) {
this(context ,strs);
this.mCheckIndex = checkPosition;
}
public NewECListDialog(Context context , String[] strs , int checkPosition) {
this(context ,strs);
this.mCheckIndex = checkPosition;
}
public NewECListDialog(Context context , String[] strs) {
this(context);
setAdapter(new ListDialogAdapter(getContext(), Arrays.asList(strs)));
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(mListener != null) {
mListener.onDialogItemClick(this , position);
}
dismiss();
}
public void setAdapter(ListAdapter adapter) {
mListView.setAdapter(adapter);
}
public class ListDialogAdapter extends IBaseAdapter<String> {
public ListDialogAdapter(Context ctx, List<String> data) {
super(ctx, data);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = this.mLayoutInflater.inflate(R.layout.listitem_dialog_new , null);
}
((TextView) convertView.findViewById(R.id.textview)).setText(getItem(position).toString());
if(mCheckIndex == position) {
convertView.findViewById(R.id.imageview).setVisibility(View.VISIBLE);
} else {
convertView.findViewById(R.id.imageview).setVisibility(View.GONE);
}
return convertView;
}
}
public void setOnDialogItemClickListener(OnDialogItemClickListener l) {
this.mListener = l;
}
public interface OnDialogItemClickListener {
void onDialogItemClick(Dialog d, int position);
}
}
@@ -0,0 +1,35 @@
package cn.shangyu.gdxzExpert.widget;
import android.text.NoCopySpan;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.view.MotionEvent;
import android.widget.TextView;
public class OverLinkMovementMethod extends LinkMovementMethod {
public static boolean canScroll = false;
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if(action == MotionEvent.ACTION_MOVE){
if(!canScroll){
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
public static MovementMethod getInstance() {
if (sInstance == null)
sInstance = new OverLinkMovementMethod();
return sInstance;
}
private static OverLinkMovementMethod sInstance;
private static Object FROM_BELOW = new NoCopySpan.Concrete();
}
@@ -0,0 +1,742 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import cn.shangyu.gdxzExpert.R;
public class PullToRefreshExpandableListView extends ExpandableListView
implements
AbsListView.OnScrollListener {
private static final String TAG = "PullToRefreshExpandableListView";
private static final int TAP_TO_REFRESH = 1;
private static final int PULL_TO_REFRESH = 2;
private static final int RELEASE_TO_REFRESH = 3;
private static final int REFRESHING = 4;
private OnRefreshListener mOnRefreshListener;
private OnScrollListener mOnScrollListener;
private LayoutInflater mInflater;
private RelativeLayout mRefreshView;
private TextView mRefreshViewText;
private ImageView mRefreshViewImage;
private ProgressBar mRefreshViewProgress;
private TextView mRefreshViewLastUpdated;
private int mCurrentScrollState;
private int mRefreshState;
private RotateAnimation mFlipAnimation;
private RotateAnimation mReverseFlipAnimation;
private int mRefreshViewHeight;
private int mRefreshOriginalTopPadding;
private int mLastMotionY;
private boolean isInInitState;
public PullToRefreshExpandableListView(Context context) {
super(context);
init(context);
}
public PullToRefreshExpandableListView(Context context, AttributeSet attrs) {
super(context,attrs);
init(context);
}
public PullToRefreshExpandableListView(Context context,AttributeSet attrs, int defStyle) {
super(context,attrs,defStyle);
init(context);
}
private void init(Context context){
mFlipAnimation = new RotateAnimation(0,-180,
RotateAnimation.RELATIVE_TO_SELF,0.5f,
RotateAnimation.RELATIVE_TO_SELF,0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(250);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180,0,
RotateAnimation.RELATIVE_TO_SELF,0.5f,
RotateAnimation.RELATIVE_TO_SELF,0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(250);
mReverseFlipAnimation.setFillAfter(true);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header, this,false);
mRefreshViewText = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);
mRefreshViewImage = (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);
mRefreshViewProgress = (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);
// mRefreshViewLastUpdated = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);
mRefreshViewImage.setMinimumHeight(50);
mRefreshView.setOnClickListener(new OnClickRefreshListener());
mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
mRefreshState = TAP_TO_REFRESH;
addHeaderView(mRefreshView);
super.setOnScrollListener(this);
measureView(mRefreshView);
mRefreshViewHeight = mRefreshView.getMeasuredHeight();
}
private void measureView(View child){
ViewGroup.LayoutParams p = child.getLayoutParams();
if(p == null){
p = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0+0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if(lpHeight > 0){
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
}else{
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec,childHeightSpec);
}
private class OnClickRefreshListener implements OnClickListener{
@Override
public void onClick(View v) {
if(mRefreshState != REFRESHING){
prepareForRefresh();
onRefresh();
}
}
}
public interface OnRefreshListener{
public void onRefresh();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setSelection(1);
}
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
setSelection(1);
}
@Override
public void setOnScrollListener(OnScrollListener l) {
mOnScrollListener = l;
}
public void setOnRefreshListener(OnRefreshListener onRefreshListener){
mOnRefreshListener = onRefreshListener;
}
public void setLastUpdated(CharSequence lastUpdated){
if(lastUpdated != null){
mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
mRefreshViewLastUpdated.setText(lastUpdated);
}else{
mRefreshViewLastUpdated.setVisibility(View.GONE);
}
}
public boolean onTouchEvent(MotionEvent event) {
final int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (!isVerticalScrollBarEnabled()) {
setVerticalScrollBarEnabled(true);
}
if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
if ((mRefreshView.getBottom() > mRefreshViewHeight
|| mRefreshView.getTop() >= 0)
&& mRefreshState == RELEASE_TO_REFRESH) {
// Initiate the refresh
mRefreshState = REFRESHING;
prepareForRefresh();
onRefresh();
} else if (mRefreshView.getBottom() < mRefreshViewHeight
|| mRefreshView.getTop() < 0) {
// Abort refresh and scroll down below the refresh view
resetHeader();
setSelection(1);
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
applyHeaderPadding(event);
break;
}
return super.onTouchEvent(event);
}
private void applyHeaderPadding(MotionEvent ev) {
final int historySize = ev.getHistorySize();
// Workaround for getPointerCount() which is unavailable in 1.5
// (it's always 1 in 1.5)
int pointerCount = 1;
try {
Method method = MotionEvent.class.getMethod("getPointerCount");
pointerCount = (Integer)method.invoke(ev);
} catch (NoSuchMethodException e) {
pointerCount = 1;
} catch (IllegalArgumentException e) {
throw e;
} catch (IllegalAccessException e) {
System.err.println("unexpected " + e);
} catch (InvocationTargetException e) {
System.err.println("unexpected " + e);
}
for (int h = 0; h < historySize; h++) {
for (int p = 0; p < pointerCount; p++) {
if (mRefreshState == RELEASE_TO_REFRESH) {
if (isVerticalFadingEdgeEnabled()) {
setVerticalScrollBarEnabled(false);
}
int historicalY = 0;
try {
// For Android > 2.0
Method method = MotionEvent.class.getMethod(
"getHistoricalY", Integer.TYPE, Integer.TYPE);
historicalY = ((Float) method.invoke(ev, p, h)).intValue();
} catch (NoSuchMethodException e) {
// For Android < 2.0
historicalY = (int) (ev.getHistoricalY(h));
} catch (IllegalArgumentException e) {
throw e;
} catch (IllegalAccessException e) {
System.err.println("unexpected " + e);
} catch (InvocationTargetException e) {
System.err.println("unexpected " + e);
}
// Calculate the padding to apply, we divide by 1.7 to
// simulate a more resistant effect during pull.
int topPadding = (int) (((historicalY - mLastMotionY)
- mRefreshViewHeight) / 1.7);
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
topPadding,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
}
}
}
private void resetHeaderPadding() {
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
mRefreshOriginalTopPadding,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
private void resetHeader() {
if (mRefreshState != TAP_TO_REFRESH) {
mRefreshState = TAP_TO_REFRESH;
resetHeaderPadding();
// Set refresh view text to the pull label
// mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
// Replace refresh drawable with arrow drawable
// mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);
// Clear the full rotation animation
mRefreshViewImage.clearAnimation();
// Hide progress bar and arrow.
mRefreshViewImage.setVisibility(View.GONE);
mRefreshViewProgress.setVisibility(View.GONE);
}
}
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// When the refresh view is completely visible, change the text to say
// "Release to refresh..." and flip the arrow drawable.
if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL
&& mRefreshState != REFRESHING) {
if (firstVisibleItem == 0) {
mRefreshViewImage.setVisibility(View.VISIBLE);
if((mRefreshView.getBottom() > mRefreshViewHeight + 20
|| mRefreshView.getTop() >= 0)
&& mRefreshState == PULL_TO_REFRESH){
// mRefreshViewText.setText(R.string.pull_to_refresh_release_label);
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mFlipAnimation);
mRefreshState = RELEASE_TO_REFRESH;
}else if(mRefreshState == RELEASE_TO_REFRESH
&&mRefreshView.getBottom() < mRefreshViewHeight + 20){
mRefreshViewImage.setVisibility(View.GONE);
resetHeader();
}else if(mRefreshView.getBottom() == mRefreshViewHeight
&& mRefreshState == TAP_TO_REFRESH){
//不作为
mRefreshViewImage.setVisibility(View.GONE);
resetHeader();
} else if(mRefreshView.getBottom() < mRefreshViewHeight + 20
&& mRefreshState == TAP_TO_REFRESH){
// mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);
mRefreshState = PULL_TO_REFRESH;
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mReverseFlipAnimation);
}
} else {
mRefreshViewImage.setVisibility(View.GONE);
resetHeader();
}
} else if (mCurrentScrollState == SCROLL_STATE_FLING
&& firstVisibleItem == 0
&& mRefreshState != REFRESHING) {
setSelection(1);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,
visibleItemCount, totalItemCount);
}
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCurrentScrollState = scrollState;
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
public void prepareForRefresh() {
resetHeaderPadding();
mRefreshViewImage.setVisibility(View.GONE);
// We need this hack, otherwise it will keep the previous drawable.
mRefreshViewImage.setImageDrawable(null);
mRefreshViewProgress.setVisibility(View.VISIBLE);
// Set refresh view text to the refreshing label
// mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);
mRefreshState = REFRESHING;
}
public void onRefresh() {
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
resetHeader();
}
}
public void onRefreshComplete(CharSequence lastUpdated) {
setLastUpdated(lastUpdated);
onRefreshComplete();
}
public void onRefreshComplete() {
resetHeader();
// If refresh view is visible when loading completes, scroll down to
// the next item.
if (mRefreshView.getBottom() > 0) {
invalidateViews();
setSelection(1);
}
}
}
@@ -0,0 +1,259 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import java.math.BigDecimal;
import cn.shangyu.gdxzExpert.R;
public class RatingBar extends LinearLayout {
/**
* 是否可点击
*/
private boolean mClickable;
/**
* 星星总数
*/
private int starCount;
/**
* 星星的点击事件
*/
private OnRatingChangeListener onRatingChangeListener;
/**
* 每个星星的大小
*/
private float starImageSize;
/**
* 每个星星的间距
*/
private float starPadding;
/**
* 星星的显示数量,支持小数点
*/
private float starStep;
/**
* 空白的默认星星图片
*/
private Drawable starEmptyDrawable;
/**
* 选中后的星星填充图片
*/
private Drawable starFillDrawable;
/**
* 半颗星的图片
*/
private Drawable starHalfDrawable;
/**
* 每次点击星星所增加的量是整个还是半个
*/
private StepSize stepSize;
/**
* 设置半星的图片资源文件
*
* @param starHalfDrawable
*/
public void setStarHalfDrawable(Drawable starHalfDrawable) {
this.starHalfDrawable = starHalfDrawable;
}
/**
* 设置满星的图片资源文件
*
* @param starFillDrawable
*/
public void setStarFillDrawable(Drawable starFillDrawable) {
this.starFillDrawable = starFillDrawable;
}
/**
* 设置空白和默认的图片资源文件
*
* @param starEmptyDrawable
*/
public void setStarEmptyDrawable(Drawable starEmptyDrawable) {
this.starEmptyDrawable = starEmptyDrawable;
}
/**
* 设置星星是否可以点击操作
*
* @param clickable
*/
public void setClickable(boolean clickable) {
this.mClickable = clickable;
}
/**
* 设置星星点击事件
*
* @param onRatingChangeListener
*/
public void setOnRatingChangeListener(OnRatingChangeListener onRatingChangeListener) {
this.onRatingChangeListener = onRatingChangeListener;
}
/**
* 设置星星的大小
*
* @param starImageSize
*/
public void setStarImageSize(float starImageSize) {
this.starImageSize = starImageSize;
}
public void setStepSize(StepSize stepSize) {
this.stepSize = stepSize;
}
/**
* 构造函数
* 获取xml中设置的资源文件
*
* @param context
* @param attrs
*/
public RatingBar(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.HORIZONTAL);
TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RatingBar);
starImageSize = mTypedArray.getDimension(R.styleable.RatingBar_starImageSize, 20);
starPadding = mTypedArray.getDimension(R.styleable.RatingBar_starPadding, 10);
starStep = mTypedArray.getFloat(R.styleable.RatingBar_starStep, 1.0f);
stepSize = StepSize.fromStep(mTypedArray.getInt(R.styleable.RatingBar_stepSize, 1));
starCount = mTypedArray.getInteger(R.styleable.RatingBar_starCount, 5);
starEmptyDrawable = mTypedArray.getDrawable(R.styleable.RatingBar_starEmpty);
starFillDrawable = mTypedArray.getDrawable(R.styleable.RatingBar_starFill);
starHalfDrawable = mTypedArray.getDrawable(R.styleable.RatingBar_starHalf);
mClickable = mTypedArray.getBoolean(R.styleable.RatingBar_clickable, true);
mTypedArray.recycle();
for (int i = 0; i < starCount; ++i) {
final ImageView imageView = getStarImageView();
imageView.setImageDrawable(starEmptyDrawable);
imageView.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
if (mClickable) {
//浮点数的整数部分
int fint = (int) starStep;
BigDecimal b1 = new BigDecimal(Float.toString(starStep));
BigDecimal b2 = new BigDecimal(Integer.toString(fint));
//浮点数的小数部分
float fPoint = b1.subtract(b2).floatValue();
if (fPoint == 0) {
fint -= 1;
}
if (indexOfChild(v) > fint) {
setStar(indexOfChild(v) + 1);
} else if (indexOfChild(v) == fint) {
if (stepSize == StepSize.Full) {//如果是满星 就不考虑半颗星了
return;
}
//点击之后默认每次先增加一颗星,再次点击变为半颗星
if (imageView.getDrawable().getCurrent().getConstantState().equals(starHalfDrawable.getConstantState())) {
setStar(indexOfChild(v) + 1);
} else {
setStar(indexOfChild(v) + 0.5f);
}
} else {
setStar(indexOfChild(v) + 1f);
}
}
}
}
);
addView(imageView);
}
setStar(starStep);
}
/**
* 设置每颗星星的参数
*
* @return
*/
private ImageView getStarImageView() {
ImageView imageView = new ImageView(getContext());
LayoutParams layout = new LayoutParams(
Math.round(starImageSize), Math.round(starImageSize));//设置每颗星星在线性布局的大小
layout.setMargins(0, 0, Math.round(starPadding), 0);//设置每颗星星在线性布局的间距
imageView.setLayoutParams(layout);
imageView.setAdjustViewBounds(true);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageDrawable(starEmptyDrawable);
imageView.setMinimumWidth(10);
imageView.setMaxHeight(10);
return imageView;
}
/**
* 设置星星的个数
*
* @param rating
*/
public void setStar(float rating) {
if (onRatingChangeListener != null) {
onRatingChangeListener.onRatingChange(rating);
}
this.starStep = rating;
//浮点数的整数部分
int fint = (int) rating;
BigDecimal b1 = new BigDecimal(Float.toString(rating));
BigDecimal b2 = new BigDecimal(Integer.toString(fint));
//浮点数的小数部分
float fPoint = b1.subtract(b2).floatValue();
//设置选中的星星
for (int i = 0; i < fint; ++i) {
((ImageView) getChildAt(i)).setImageDrawable(starFillDrawable);
}
//设置没有选中的星星
for (int i = fint; i < starCount; i++) {
((ImageView) getChildAt(i)).setImageDrawable(starEmptyDrawable);
}
//小数点默认增加半颗星
if (fPoint > 0) {
((ImageView) getChildAt(fint)).setImageDrawable(starHalfDrawable);
}
}
/**
* 操作星星的点击事件
*/
public interface OnRatingChangeListener {
/**
* 选中的星星的个数
*
* @param
*/
void onRatingChange(float ratingCount);
}
/**
* 星星每次增加的方式整星还是半星,枚举类型
* 类似于View.GONE
*/
public enum StepSize {
Half(0), Full(1);
int step;
StepSize(int step) {
this.step = step;
}
public static StepSize fromStep(int step) {
for (StepSize f : values()) {
if (f.step == step) {
return f;
}
}
throw new IllegalArgumentException();
}
}
}
@@ -0,0 +1,39 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
/**
*
* ResizeLayout.java
* @author gaofei
* @date 2015-9-8 上午9:14:27
* Copyright (C) 2015 河南商宇科技有限公司
*
* 功能说明:自定义可以设置布局size改变监听的LinearLayout
* 用于注册时,软键盘弹出隐藏注册界面logo
*/
public class ResizeLayout extends LinearLayout {
private OnResizeListener mListener;
public interface OnResizeListener {
void OnResize(int w, int h, int oldw, int oldh);
}
public void setOnResizeListener(OnResizeListener l) {
mListener = l;
}
public ResizeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mListener != null) {
mListener.OnResize(w, h, oldw, oldh);
}
}
}
@@ -0,0 +1,21 @@
package cn.shangyu.gdxzExpert.widget;
import android.text.Editable;
import android.text.TextWatcher;
public abstract class SimpleTextWatcher implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
}
@@ -0,0 +1,172 @@
package cn.shangyu.gdxzExpert.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
import cn.shangyu.gdxzExpert.R;
@SuppressLint("HandlerLeak")
public class SnapUpCountDownTimerView extends LinearLayout {
private TextView tv_hour_decade;
private TextView tv_hour_unit;
private TextView tv_min_decade;
private TextView tv_min_unit;
private TextView tv_sec_decade;
private TextView tv_sec_unit;
private Context context;
private int hour_decade;
private int hour_unit;
private int min_decade;
private int min_unit;
private int sec_decade;
private int sec_unit;
private Timer timer;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
countDown();
}
};
public SnapUpCountDownTimerView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.view_countdowntimer, this);
tv_hour_decade = (TextView) view.findViewById(R.id.tv_hour_decade);
tv_hour_unit = (TextView) view.findViewById(R.id.tv_hour_unit);
tv_min_decade = (TextView) view.findViewById(R.id.tv_min_decade);
tv_min_unit = (TextView) view.findViewById(R.id.tv_min_unit);
tv_sec_decade = (TextView) view.findViewById(R.id.tv_sec_decade);
tv_sec_unit = (TextView) view.findViewById(R.id.tv_sec_unit);
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.SnapUpCountDownTimerView);
int size = array.getInteger(R.styleable.SnapUpCountDownTimerView_viewSize, 12);
tv_hour_decade.setTextSize(size);
tv_hour_unit.setTextSize(size);
tv_min_decade.setTextSize(size);
tv_min_unit.setTextSize(size);
tv_sec_decade.setTextSize(size);
tv_sec_unit.setTextSize(size);
((TextView)view.findViewById(R.id.colon_minute)).setTextSize(size);
((TextView)view.findViewById(R.id.colon_hour)).setTextSize(size);
}
public void start() {
if (timer == null) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(0);
}
}, 0, 1000);
}
}
public void stop() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void setTime(int hour, int min, int sec) {
if (hour >= 60 || min >= 60 || sec >= 60 || hour < 0 || min < 0
|| sec < 0) {
throw new RuntimeException("时间格式错误,请检查你的代码");
}
hour_decade = hour / 10;
hour_unit = hour - hour_decade * 10;
min_decade = min / 10;
min_unit = min - min_decade * 10;
sec_decade = sec / 10;
sec_unit = sec - sec_decade * 10;
tv_hour_decade.setText(hour_decade + "");
tv_hour_unit.setText(hour_unit + "");
tv_min_decade.setText(min_decade + "");
tv_min_unit.setText(min_unit + "");
tv_sec_decade.setText(sec_decade + "");
tv_sec_unit.setText(sec_unit + "");
}
private void countDown() {
if (isCarry4Unit(tv_sec_unit)) {
if (isCarry4Decade(tv_sec_decade)) {
if (isCarry4Unit(tv_min_unit)) {
if (isCarry4Decade(tv_min_decade)) {
if (isCarry4Unit(tv_hour_unit)) {
if (isCarry4Decade(tv_hour_decade)) {
// Toast.makeText(context, "计数完成",
// Toast.LENGTH_SHORT).show();
stop();
setTime(0, 0, 0);//重置为0
}
}
}
}
}
}
}
private boolean isCarry4Decade(TextView tv) {
int time = Integer.valueOf(tv.getText().toString());
time = time - 1;
if (time < 0) {
time = 5;
tv.setText(time + "");
return true;
} else {
tv.setText(time + "");
return false;
}
}
private boolean isCarry4Unit(TextView tv) {
int time = Integer.valueOf(tv.getText().toString());
time = time - 1;
if (time < 0) {
time = 9;
tv.setText(time + "");
return true;
} else {
tv.setText(time + "");
return false;
}
}
}
@@ -0,0 +1,170 @@
package cn.shangyu.gdxzExpert.widget;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import cn.shangyu.gdxzExpert.application.BaseApplication;
/**
*
* TimeButton.java
*
* @author gaofei
* @date 2015-9-6 下午6:59:44 Copyright (C) 2015 河南商宇科技有限公司
*
* 功能说明: 到获取验证码倒计时按钮 PS:
* 由于发现timer每次cancle()之后不能重新schedule方法,所以计时完毕只恐timer. 每次开始计时的时候重新设置timer,
* 没想到好办法初次下策
* 注意把该类的onCreate()onDestroy()和activity的onCreate()onDestroy()同步处理
*/
public class TimeButton extends Button implements OnClickListener {
private long lenght = 60 * 1000;// 倒计时长度,这里给了默认60秒
private String textafter = "s";
private String textbefore = "点击获取验证码~";
private final String TIME = "time";
private final String CTIME = "ctime";
private OnClickListener mOnclickListener;
private Timer t;
private TimerTask tt;
private long time;
Map<String, Long> map = new HashMap<String, Long>();
public TimeButton(Context context) {
super(context);
setOnClickListener(this);
}
public TimeButton(Context context, AttributeSet attrs) {
super(context, attrs);
setOnClickListener(this);
}
@SuppressLint("HandlerLeak")
Handler han = new Handler() {
public void handleMessage(android.os.Message msg) {
TimeButton.this.setText(time / 1000 + textafter);
time -= 1000;
if (time < 0) {
clearTimer();
}
};
};
private void initTimer() {
time = lenght;
t = new Timer();
tt = new TimerTask() {
@Override
public void run() {
Log.e("yung", time / 1000 + "");
han.sendEmptyMessage(0x01);
}
};
}
public void clearTimer() {
TimeButton.this.setEnabled(true);
TimeButton.this.setText(textbefore);
if (tt != null) {
tt.cancel();
tt = null;
}
if (t != null)
t.cancel();
t = null;
}
@Override
public void setOnClickListener(OnClickListener l) {
if (l instanceof TimeButton) {
super.setOnClickListener(l);
} else
this.mOnclickListener = l;
}
public void onClick(View v) {
if (mOnclickListener != null)
mOnclickListener.onClick(v);
// startTimer();
// t.scheduleAtFixedRate(task, delay, period);
}
public void startTimer() {
initTimer();
this.setText(time / 1000 + textafter);
this.setEnabled(false);
t.schedule(tt, 0, 1000);
}
/**
* 和activity的onDestroy()方法同步
*/
public void onDestroy() {
// if (BaseApplication.timemap == null)
// BaseApplication.timemap = new HashMap<String, Long>();
// BaseApplication.timemap.put(TIME, time);
// BaseApplication.timemap.put(CTIME, System.currentTimeMillis());
clearTimer();
}
/**
* 和activity的onCreate()方法同步
*/
public void onCreate() {
Log.e("yung", BaseApplication.timemap + "");
if (BaseApplication.timemap == null)
return;
// if (BaseApplication.timemap.size() <= 0)// 这里表示没有上次未完成的计时
// return;
// long time = System.currentTimeMillis()
// - BaseApplication.timemap.get(CTIME)
// - BaseApplication.timemap.get(TIME);
// BaseApplication.timemap.clear();
// if (time > 0)
// return;
// else {
initTimer();
this.time = Math.abs(time);
t.schedule(tt, 0, 1000);
this.setText(time + textafter);
this.setEnabled(false);
// }
}
/** * 设置计时时候显示的文本 */
public TimeButton setTextAfter(String text1) {
this.textafter = text1;
return this;
}
/** * 设置点击之前的文本 */
public TimeButton setTextBefore(String text0) {
this.textbefore = text0;
this.setText(textbefore);
return this;
}
/**
* 设置到计时长度
*
* @param lenght
* 时间 默认毫秒
* @return
*/
public TimeButton setLenght(long lenght) {
this.lenght = lenght;
return this;
}
}
@@ -0,0 +1,171 @@
package cn.shangyu.gdxzExpert.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import cn.shangyu.gdxzExpert.R;
public class WordWrapView extends ViewGroup {
private int padding_hor =0;//子view水平方向padding
private int padding_vertical=0;//子view垂直方向padding
private int margin_hor=0;//子view之间的水平间距
private int margin_vertical=0;//行间距
private int num = 0;//最多字个数
/**
* @param context
*/
public WordWrapView(Context context) {
super(context);
}
/**
* @param context
* @param attrs
*/
public WordWrapView(Context context, AttributeSet attrs) {
super(context, attrs);
initAttrs(context,attrs);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public WordWrapView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initAttrs(context,attrs);
}
//获取属性值
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.WordWrapView);
padding_hor= (int) ta.getDimension(R.styleable.WordWrapView_padding_hor,8);
padding_vertical= (int) ta.getDimension(R.styleable.WordWrapView_padding_vertical,1);
margin_hor= (int) ta.getDimension(R.styleable.WordWrapView_margin_hor,20);
margin_vertical= (int) ta.getDimension(R.styleable.WordWrapView_margin_vertial,10);
ta.recycle();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount=getChildCount();
int acturalWith=r-l;//实际宽度
int x=0;
int y=0;
int rows=1;
for (int i = 0; i <childCount ; i++) {//判断累积高度
View view=getChildAt(i);
int width=view.getMeasuredWidth();
int height=view.getMeasuredHeight();
x+=width+margin_hor;
if(x>acturalWith-margin_hor){
if(i!=0){
x=width+margin_hor;
rows++;
}
}
//当一个子view长度超出父view长度时
if(x>acturalWith-margin_hor){
if(view instanceof TextView){//判断单个高度
TextView tv= (TextView) view;
if(num==0){
int wordNum=tv.getText().toString().length();
num=wordNum*(acturalWith-2*margin_hor-2* padding_hor)/(width-2* padding_hor)-1;
}
String text=tv.getText().toString();
text=text.substring(0,num)+"...";
tv.setText(text);
}
x=acturalWith-margin_hor;
width=acturalWith-2*margin_hor;
}
y = rows * (height + margin_vertical);
view.layout(x - width, y - height, x, y);
}
}
public float getCharacterWidth(String text, float size) {
if (null == text || "".equals(text))
return 0;
float width = 0;
Paint paint = new Paint();
paint.setTextSize(size);
float text_width = paint.measureText(text);// 得到总体长度
width = text_width / text.length();// 每一个字符的长度
return width;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int x=0;//横坐标
int y=0;//纵坐标
int rows=1;//总行数
int specWidth=MeasureSpec.getSize(widthMeasureSpec);
int acturalWith=specWidth;//实际宽度
int childCount=getChildCount();
for (int i = 0; i <childCount ; i++) {
View child=getChildAt(i);
child.setPadding(padding_hor,padding_vertical, padding_hor,padding_vertical);
child.measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);
int width=child.getMeasuredWidth();
int height=child.getMeasuredHeight();
x+=width+margin_hor;
if(x>acturalWith-margin_hor){//换行
if(i!=0){
x=width+margin_hor;
rows++;
}
}
y=rows*(height+margin_vertical);
}
setMeasuredDimension(acturalWith,y+margin_vertical);
}
public int getPadding_hor() {
return padding_hor;
}
public void setPadding_hor(int padding_hor) {
this.padding_hor = padding_hor;
}
public int getPadding_vertical() {
return padding_vertical;
}
public void setPadding_vertical(int padding_vertical) {
this.padding_vertical = padding_vertical;
}
public int getMargin_hor() {
return margin_hor;
}
public void setMargin_hor(int margin_hor) {
this.margin_hor = margin_hor;
}
public int getMargin_vertical() {
return margin_vertical;
}
public void setMargin_vertical(int margin_vertical) {
this.margin_vertical = margin_vertical;
}
}
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
abstract class BaseDrawable extends Drawable implements TintableDrawable {
protected int mAlpha = 0xFF;
protected ColorFilter mColorFilter;
protected ColorStateList mTintList;
protected PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_IN;
protected PorterDuffColorFilter mTintFilter;
private DummyConstantState mConstantState = new DummyConstantState();
@Override
public int getAlpha() {
return mAlpha;
}
/**
* {@inheritDoc}
*/
@Override
public void setAlpha(int alpha) {
if (mAlpha != alpha) {
mAlpha = alpha;
invalidateSelf();
}
}
/**
* {@inheritDoc}
*/
@Override
public ColorFilter getColorFilter() {
return mColorFilter;
}
/**
* {@inheritDoc}
*/
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mColorFilter = colorFilter;
invalidateSelf();
}
/**
* {@inheritDoc}
*/
@Override
public void setTint(@ColorInt int tintColor) {
setTintList(ColorStateList.valueOf(tintColor));
}
/**
* {@inheritDoc}
*/
@Override
public void setTintList(@Nullable ColorStateList tint) {
mTintList = tint;
if (updateTintFilter()) {
invalidateSelf();
}
}
/**
* {@inheritDoc}
*/
@Override
public void setTintMode(@NonNull PorterDuff.Mode tintMode) {
mTintMode = tintMode;
if (updateTintFilter()) {
invalidateSelf();
}
}
@Override
public boolean isStateful() {
return mTintList != null && mTintList.isStateful();
}
@Override
protected boolean onStateChange(int[] state) {
return updateTintFilter();
}
private boolean updateTintFilter() {
if (mTintList == null || mTintMode == null) {
boolean hadTintFilter = mTintFilter != null;
mTintFilter = null;
return hadTintFilter;
}
int tintColor = mTintList.getColorForState(getState(), Color.TRANSPARENT);
// They made PorterDuffColorFilter.setColor() and setMode() @hide.
mTintFilter = new PorterDuffColorFilter(tintColor, mTintMode);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public int getOpacity() {
// Be safe.
return PixelFormat.TRANSLUCENT;
}
/**
* {@inheritDoc}
*/
@Override
public void draw(Canvas canvas) {
Rect bounds = getBounds();
if (bounds.width() == 0 || bounds.height() == 0) {
return;
}
int saveCount = canvas.save();
canvas.translate(bounds.left, bounds.top);
onDraw(canvas, bounds.width(), bounds.height());
canvas.restoreToCount(saveCount);
}
protected ColorFilter getColorFilterForDrawing() {
return mColorFilter != null ? mColorFilter : mTintFilter;
}
protected abstract void onDraw(Canvas canvas, int width, int height);
// Workaround LayerDrawable.ChildDrawable which calls getConstantState().newDrawable()
// without checking for null.
// We are never inflated from XML so the protocol of ConstantState does not apply to us. In
// order to make LayerDrawable happy, we return ourselves from DummyConstantState.newDrawable().
@Override
public ConstantState getConstantState() {
return mConstantState;
}
private class DummyConstantState extends ConstantState {
@Override
public int getChangingConfigurations() {
return 0;
}
@NonNull
@Override
public Drawable newDrawable() {
return BaseDrawable.this;
}
}
}
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
class ClipDrawableCompat extends ClipDrawable implements TintableDrawable {
private static final String TAG = ClipDrawableCompat.class.getSimpleName();
private Drawable mDrawable;
private DummyConstantState mConstantState = new DummyConstantState();
public ClipDrawableCompat(Drawable drawable, int gravity, int orientation) {
super(drawable, gravity, orientation);
mDrawable = drawable;
}
@Nullable
@Override
public Drawable getDrawable() {
return mDrawable;
}
@Override
public void setTint(int tintColor) {
if (mDrawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) mDrawable).setTint(tintColor);
} else {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
super.setTint(tintColor);
}
}
@Override
public void setTintList(ColorStateList tint) {
if (mDrawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) mDrawable).setTintList(tint);
} else {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
super.setTintList(tint);
}
}
@Override
public void setTintMode(PorterDuff.Mode tintMode) {
if (mDrawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) mDrawable).setTintMode(tintMode);
} else {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
super.setTintMode(tintMode);
}
}
// Workaround LayerDrawable.ChildDrawable which calls getConstantState().newDrawable()
// without checking for null.
// We are never inflated from XML so the protocol of ConstantState does not apply to us. In
// order to make LayerDrawable happy, we return ourselves from DummyConstantState.newDrawable().
@Override
public ConstantState getConstantState() {
return mConstantState;
}
private class DummyConstantState extends ConstantState {
@Override
public int getChangingConfigurations() {
return 0;
}
@NonNull
@Override
public Drawable newDrawable() {
return ClipDrawableCompat.this;
}
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.graphics.PorterDuff;
public class DrawableCompat {
/**
* Parses a {@link PorterDuff.Mode} from a tintMode attribute's enum value.
*/
public static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) {
switch (value) {
case 3: return PorterDuff.Mode.SRC_OVER;
case 5: return PorterDuff.Mode.SRC_IN;
case 9: return PorterDuff.Mode.SRC_ATOP;
case 14: return PorterDuff.Mode.MULTIPLY;
case 15: return PorterDuff.Mode.SCREEN;
case 16: return PorterDuff.Mode.ADD;
default: return defaultMode;
}
}
}
@@ -0,0 +1,671 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RatingBar;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.TintTypedArray;
import cn.shangyu.gdxzExpert.R;
// AppCompatRatingBar will add undesired measuring behavior.
@SuppressLint("AppCompatCustomView")
public class MaterialRatingBar extends RatingBar {
private static final String TAG = MaterialRatingBar.class.getSimpleName();
private TintInfo mProgressTintInfo = new TintInfo();
private MaterialRatingDrawable mDrawable;
private OnRatingChangeListener mOnRatingChangeListener;
private float mLastKnownRating;
public MaterialRatingBar(Context context) {
super(context);
init(null, 0);
}
public MaterialRatingBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public MaterialRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
@SuppressWarnings("RestrictedApi")
private void init(AttributeSet attrs, int defStyleAttr) {
Context context = getContext();
TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.MaterialRatingBar, defStyleAttr, 0);
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressTint)) {
mProgressTintInfo.mProgressTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_progressTint);
mProgressTintInfo.mHasProgressTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressTintMode)) {
mProgressTintInfo.mProgressTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_progressTintMode, -1), null);
mProgressTintInfo.mHasProgressTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_secondaryProgressTint)) {
mProgressTintInfo.mSecondaryProgressTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_secondaryProgressTint);
mProgressTintInfo.mHasSecondaryProgressTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_secondaryProgressTintMode)) {
mProgressTintInfo.mSecondaryProgressTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_secondaryProgressTintMode, -1), null);
mProgressTintInfo.mHasSecondaryProgressTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressBackgroundTint)) {
mProgressTintInfo.mProgressBackgroundTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_progressBackgroundTint);
mProgressTintInfo.mHasProgressBackgroundTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressBackgroundTintMode)) {
mProgressTintInfo.mProgressBackgroundTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_progressBackgroundTintMode, -1), null);
mProgressTintInfo.mHasProgressBackgroundTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_indeterminateTint)) {
mProgressTintInfo.mIndeterminateTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_indeterminateTint);
mProgressTintInfo.mHasIndeterminateTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_indeterminateTintMode)) {
mProgressTintInfo.mIndeterminateTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_indeterminateTintMode, -1), null);
mProgressTintInfo.mHasIndeterminateTintMode = true;
}
boolean fillBackgroundStars = a.getBoolean(
R.styleable.MaterialRatingBar_mrb_fillBackgroundStars, isIndicator());
a.recycle();
mDrawable = new MaterialRatingDrawable(getContext(), fillBackgroundStars);
mDrawable.setStarCount(getNumStars());
setProgressDrawable(mDrawable);
// setSecondaryProgress();
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// setMax(100);
// setMin(10);
// setProgress(0);
// }
}
@Override
public void setNumStars(int numStars) {
super.setNumStars(numStars);
// mDrawable can be null during super class initialization.
if (mDrawable != null) {
mDrawable.setStarCount(numStars);
}
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = getMeasuredHeight();
int width = Math.round(height * mDrawable.getTileRatio() * getNumStars());
setMeasuredDimension(View.resolveSizeAndState(width, widthMeasureSpec, 0), height);
}
@Override
public void setProgressDrawable(Drawable d) {
super.setProgressDrawable(d);
// mProgressTintInfo can be null during super class initialization.
if (mProgressTintInfo != null) {
applyProgressTints();
}
}
@Override
public void setIndeterminateDrawable(Drawable d) {
super.setIndeterminateDrawable(d);
// mProgressTintInfo can be null during super class initialization.
if (mProgressTintInfo != null) {
applyIndeterminateTint();
}
}
/**
* @deprecated Use {@link #getSupportProgressTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getProgressTintList() {
// Samsung Android 10 might call this in super class constructor.
if (mProgressTintInfo == null) {
return null;
}
logRatingBarTintWarning();
return getSupportProgressTintList();
}
/**
* @deprecated Use {@link #setSupportProgressTintList(ColorStateList)} instead.
*/
@Override
public void setProgressTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportProgressTintList(tint);
}
/**
* @deprecated Use {@link #getSupportProgressTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getProgressTintMode() {
logRatingBarTintWarning();
return getSupportProgressTintMode();
}
/**
* @deprecated Use {@link #setSupportProgressTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportProgressTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportSecondaryProgressTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getSecondaryProgressTintList() {
logRatingBarTintWarning();
return getSupportSecondaryProgressTintList();
}
/**
* @deprecated Use {@link #setSupportSecondaryProgressTintList(ColorStateList)} instead.
*/
@Override
public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportSecondaryProgressTintList(tint);
}
/**
* @deprecated Use {@link #getSupportSecondaryProgressTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getSecondaryProgressTintMode() {
logRatingBarTintWarning();
return getSupportSecondaryProgressTintMode();
}
/**
* @deprecated Use {@link #setSupportSecondaryProgressTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportSecondaryProgressTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportProgressBackgroundTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getProgressBackgroundTintList() {
logRatingBarTintWarning();
return getSupportProgressBackgroundTintList();
}
/**
* @deprecated Use {@link #setSupportProgressBackgroundTintList(ColorStateList)} instead.
*/
@Override
public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportProgressBackgroundTintList(tint);
}
/**
* @deprecated Use {@link #getSupportProgressBackgroundTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getProgressBackgroundTintMode() {
logRatingBarTintWarning();
return getSupportProgressBackgroundTintMode();
}
/**
* @deprecated Use {@link #setSupportProgressBackgroundTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportProgressBackgroundTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportIndeterminateTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getIndeterminateTintList() {
logRatingBarTintWarning();
return getSupportIndeterminateTintList();
}
/**
* @deprecated Use {@link #setSupportIndeterminateTintList(ColorStateList)} instead.
*/
@Override
public void setIndeterminateTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportIndeterminateTintList(tint);
}
/**
* @deprecated Use {@link #getSupportIndeterminateTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getIndeterminateTintMode() {
logRatingBarTintWarning();
return getSupportIndeterminateTintMode();
}
/**
* @deprecated Use {@link #setSupportIndeterminateTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportIndeterminateTintMode(tintMode);
}
private void logRatingBarTintWarning() {
Log.w(TAG, "Non-support version of tint method called, this is error-prone and will crash" +
" below Lollipop if you are calling it as a method of RatingBar instead of" +
" MaterialRatingBar");
}
/**
* @see RatingBar#getProgressTintList()
*/
@Nullable
public ColorStateList getSupportProgressTintList() {
return mProgressTintInfo.mProgressTintList;
}
/**
* @see RatingBar#setProgressTintList(ColorStateList)
*/
public void setSupportProgressTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mProgressTintList = tint;
mProgressTintInfo.mHasProgressTintList = true;
applyPrimaryProgressTint();
}
/**
* @see RatingBar#getProgressTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportProgressTintMode() {
return mProgressTintInfo.mProgressTintMode;
}
/**
* @see RatingBar#setProgressTintMode(PorterDuff.Mode)
*/
public void setSupportProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mProgressTintMode = tintMode;
mProgressTintInfo.mHasProgressTintMode = true;
applyPrimaryProgressTint();
}
/**
* @see RatingBar#getSecondaryProgressTintList()
*/
@Nullable
public ColorStateList getSupportSecondaryProgressTintList() {
return mProgressTintInfo.mSecondaryProgressTintList;
}
/**
* @see RatingBar#setSecondaryProgressTintList(ColorStateList)
*/
public void setSupportSecondaryProgressTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mSecondaryProgressTintList = tint;
mProgressTintInfo.mHasSecondaryProgressTintList = true;
applySecondaryProgressTint();
}
/**
* @see RatingBar#getSecondaryProgressTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportSecondaryProgressTintMode() {
return mProgressTintInfo.mSecondaryProgressTintMode;
}
/**
* @see RatingBar#setSecondaryProgressTintMode(PorterDuff.Mode)
*/
public void setSupportSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mSecondaryProgressTintMode = tintMode;
mProgressTintInfo.mHasSecondaryProgressTintMode = true;
applySecondaryProgressTint();
}
/**
* @see RatingBar#getProgressBackgroundTintList()
*/
@Nullable
public ColorStateList getSupportProgressBackgroundTintList() {
return mProgressTintInfo.mProgressBackgroundTintList;
}
/**
* @see RatingBar#setProgressBackgroundTintList(ColorStateList)
*/
public void setSupportProgressBackgroundTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mProgressBackgroundTintList = tint;
mProgressTintInfo.mHasProgressBackgroundTintList = true;
applyProgressBackgroundTint();
}
/**
* @see RatingBar#getProgressBackgroundTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportProgressBackgroundTintMode() {
return mProgressTintInfo.mProgressBackgroundTintMode;
}
/**
* @see RatingBar#setProgressBackgroundTintMode(PorterDuff.Mode)
*/
public void setSupportProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mProgressBackgroundTintMode = tintMode;
mProgressTintInfo.mHasProgressBackgroundTintMode = true;
applyProgressBackgroundTint();
}
/**
* @see RatingBar#getIndeterminateTintList()
*/
@Nullable
public ColorStateList getSupportIndeterminateTintList() {
return mProgressTintInfo.mIndeterminateTintList;
}
/**
* @see RatingBar#setIndeterminateTintList(ColorStateList)
*/
public void setSupportIndeterminateTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mIndeterminateTintList = tint;
mProgressTintInfo.mHasIndeterminateTintList = true;
applyIndeterminateTint();
}
/**
* @see RatingBar#getIndeterminateTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportIndeterminateTintMode() {
return mProgressTintInfo.mIndeterminateTintMode;
}
/**
* @see RatingBar#setIndeterminateTintMode(PorterDuff.Mode)
*/
public void setSupportIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mIndeterminateTintMode = tintMode;
mProgressTintInfo.mHasIndeterminateTintMode = true;
applyIndeterminateTint();
}
private void applyProgressTints() {
if (getProgressDrawable() == null) {
return;
}
applyPrimaryProgressTint();
applyProgressBackgroundTint();
applySecondaryProgressTint();
}
private void applyPrimaryProgressTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasProgressTintList || mProgressTintInfo.mHasProgressTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.progress, true);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mProgressTintList,
mProgressTintInfo.mHasProgressTintList, mProgressTintInfo.mProgressTintMode,
mProgressTintInfo.mHasProgressTintMode);
}
}
}
private void applySecondaryProgressTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasSecondaryProgressTintList
|| mProgressTintInfo.mHasSecondaryProgressTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.secondaryProgress,
false);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mSecondaryProgressTintList,
mProgressTintInfo.mHasSecondaryProgressTintList,
mProgressTintInfo.mSecondaryProgressTintMode,
mProgressTintInfo.mHasSecondaryProgressTintMode);
}
}
}
private void applyProgressBackgroundTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasProgressBackgroundTintList
|| mProgressTintInfo.mHasProgressBackgroundTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.background, false);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mProgressBackgroundTintList,
mProgressTintInfo.mHasProgressBackgroundTintList,
mProgressTintInfo.mProgressBackgroundTintMode,
mProgressTintInfo.mHasProgressBackgroundTintMode);
}
}
}
private Drawable getTintTargetFromProgressDrawable(int layerId, boolean shouldFallback) {
Drawable progressDrawable = getProgressDrawable();
if (progressDrawable == null) {
return null;
}
progressDrawable.mutate();
Drawable layerDrawable = null;
if (progressDrawable instanceof LayerDrawable) {
layerDrawable = ((LayerDrawable) progressDrawable).findDrawableByLayerId(layerId);
}
if (layerDrawable == null && shouldFallback) {
layerDrawable = progressDrawable;
}
return layerDrawable;
}
private void applyIndeterminateTint() {
Drawable indeterminateDrawable = getIndeterminateDrawable();
if (indeterminateDrawable == null) {
return;
}
if (mProgressTintInfo.mHasIndeterminateTintList
|| mProgressTintInfo.mHasIndeterminateTintMode) {
indeterminateDrawable.mutate();
applyTintForDrawable(indeterminateDrawable, mProgressTintInfo.mIndeterminateTintList,
mProgressTintInfo.mHasIndeterminateTintList,
mProgressTintInfo.mIndeterminateTintMode,
mProgressTintInfo.mHasIndeterminateTintMode);
}
}
// Progress drawables in this library has already rewritten tint related methods for
// compatibility.
@SuppressLint("NewApi")
private void applyTintForDrawable(Drawable drawable, ColorStateList tintList,
boolean hasTintList, PorterDuff.Mode tintMode,
boolean hasTintMode) {
if (hasTintList || hasTintMode) {
if (hasTintList) {
if (drawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) drawable).setTintList(tintList);
} else {
logDrawableTintWarning();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable.setTintList(tintList);
}
}
}
if (hasTintMode) {
if (drawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) drawable).setTintMode(tintMode);
} else {
logDrawableTintWarning();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable.setTintMode(tintMode);
}
}
}
// The drawable (or one of its children) may not have been
// stateful before applying the tint, so let's try again.
if (drawable.isStateful()) {
drawable.setState(getDrawableState());
}
}
}
private void logDrawableTintWarning() {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
}
/**
* Get the listener that is listening for rating change events.
*
* @return The listener, may be null.
*/
public OnRatingChangeListener getOnRatingChangeListener() {
return mOnRatingChangeListener;
}
/**
* Sets the listener to be called when the rating changes.
*
* @param listener The listener.
*/
public void setOnRatingChangeListener(OnRatingChangeListener listener) {
mOnRatingChangeListener = listener;
}
@Override
public synchronized void setSecondaryProgress(int secondaryProgress) {
super.setSecondaryProgress(secondaryProgress);
// HACK: Check and call our listener here because this method is always called by
// updateSecondaryProgress() from onProgressRefresh().
float rating = getRating();
if(rating<0.5)
setRating((float) 0.5);
if (mOnRatingChangeListener != null && rating != mLastKnownRating) {
mOnRatingChangeListener.onRatingChanged(this, rating);
}
mLastKnownRating = rating;
}
/**
* A callback that notifies clients when the rating has been changed. This includes changes that
* were initiated by the user through a touch gesture or arrow key/trackball as well as changes
* that were initiated programmatically. This callback <strong>will</strong> be called
* continuously while the user is dragging, different from framework's
* {@link OnRatingBarChangeListener}.
*/
public interface OnRatingChangeListener {
/**
* Notification that the rating has changed. This <strong>will</strong> be called
* continuously while the user is dragging, different from framework's
* {@link OnRatingBarChangeListener}.
*
* @param ratingBar The RatingBar whose rating has changed.
* @param rating The current rating. This will be in the range 0..numStars.
*/
void onRatingChanged(MaterialRatingBar ratingBar, float rating);
}
private static class TintInfo {
public ColorStateList mProgressTintList;
public PorterDuff.Mode mProgressTintMode;
public boolean mHasProgressTintList;
public boolean mHasProgressTintMode;
public ColorStateList mSecondaryProgressTintList;
public PorterDuff.Mode mSecondaryProgressTintMode;
public boolean mHasSecondaryProgressTintList;
public boolean mHasSecondaryProgressTintMode;
public ColorStateList mProgressBackgroundTintList;
public PorterDuff.Mode mProgressBackgroundTintMode;
public boolean mHasProgressBackgroundTintList;
public boolean mHasProgressBackgroundTintMode;
public ColorStateList mIndeterminateTintList;
public PorterDuff.Mode mIndeterminateTintMode;
public boolean mHasIndeterminateTintList;
public boolean mHasIndeterminateTintMode;
}
}
@@ -0,0 +1,668 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RatingBar;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.TintTypedArray;
import cn.shangyu.gdxzExpert.R;
// AppCompatRatingBar will add undesired measuring behavior.
@SuppressLint("AppCompatCustomView")
public class MaterialRatingBarOld extends RatingBar {
private static final String TAG = MaterialRatingBarOld.class.getSimpleName();
private TintInfo mProgressTintInfo = new TintInfo();
private MaterialRatingDrawable mDrawable;
private OnRatingChangeListener mOnRatingChangeListener;
private float mLastKnownRating;
public MaterialRatingBarOld(Context context) {
super(context);
init(null, 0);
}
public MaterialRatingBarOld(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public MaterialRatingBarOld(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
@SuppressWarnings("RestrictedApi")
private void init(AttributeSet attrs, int defStyleAttr) {
Context context = getContext();
TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.MaterialRatingBar, defStyleAttr, 0);
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressTint)) {
mProgressTintInfo.mProgressTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_progressTint);
mProgressTintInfo.mHasProgressTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressTintMode)) {
mProgressTintInfo.mProgressTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_progressTintMode, -1), null);
mProgressTintInfo.mHasProgressTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_secondaryProgressTint)) {
mProgressTintInfo.mSecondaryProgressTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_secondaryProgressTint);
mProgressTintInfo.mHasSecondaryProgressTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_secondaryProgressTintMode)) {
mProgressTintInfo.mSecondaryProgressTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_secondaryProgressTintMode, -1), null);
mProgressTintInfo.mHasSecondaryProgressTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressBackgroundTint)) {
mProgressTintInfo.mProgressBackgroundTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_progressBackgroundTint);
mProgressTintInfo.mHasProgressBackgroundTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressBackgroundTintMode)) {
mProgressTintInfo.mProgressBackgroundTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_progressBackgroundTintMode, -1), null);
mProgressTintInfo.mHasProgressBackgroundTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_indeterminateTint)) {
mProgressTintInfo.mIndeterminateTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_indeterminateTint);
mProgressTintInfo.mHasIndeterminateTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_indeterminateTintMode)) {
mProgressTintInfo.mIndeterminateTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_indeterminateTintMode, -1), null);
mProgressTintInfo.mHasIndeterminateTintMode = true;
}
boolean fillBackgroundStars = a.getBoolean(
R.styleable.MaterialRatingBar_mrb_fillBackgroundStars, isIndicator());
a.recycle();
mDrawable = new MaterialRatingDrawable(getContext(), fillBackgroundStars);
mDrawable.setStarCount(getNumStars());
setProgressDrawable(mDrawable);
// setSecondaryProgress();
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// setMax(100);
// setMin(10);
// setProgress(0);
// }
}
@Override
public void setNumStars(int numStars) {
super.setNumStars(numStars);
// mDrawable can be null during super class initialization.
if (mDrawable != null) {
mDrawable.setStarCount(numStars);
}
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = getMeasuredHeight();
int width = Math.round(height * mDrawable.getTileRatio() * getNumStars());
setMeasuredDimension(View.resolveSizeAndState(width, widthMeasureSpec, 0), height);
}
@Override
public void setProgressDrawable(Drawable d) {
super.setProgressDrawable(d);
// mProgressTintInfo can be null during super class initialization.
if (mProgressTintInfo != null) {
applyProgressTints();
}
}
@Override
public void setIndeterminateDrawable(Drawable d) {
super.setIndeterminateDrawable(d);
// mProgressTintInfo can be null during super class initialization.
if (mProgressTintInfo != null) {
applyIndeterminateTint();
}
}
/**
* @deprecated Use {@link #getSupportProgressTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getProgressTintList() {
// Samsung Android 10 might call this in super class constructor.
if (mProgressTintInfo == null) {
return null;
}
logRatingBarTintWarning();
return getSupportProgressTintList();
}
/**
* @deprecated Use {@link #setSupportProgressTintList(ColorStateList)} instead.
*/
@Override
public void setProgressTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportProgressTintList(tint);
}
/**
* @deprecated Use {@link #getSupportProgressTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getProgressTintMode() {
logRatingBarTintWarning();
return getSupportProgressTintMode();
}
/**
* @deprecated Use {@link #setSupportProgressTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportProgressTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportSecondaryProgressTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getSecondaryProgressTintList() {
logRatingBarTintWarning();
return getSupportSecondaryProgressTintList();
}
/**
* @deprecated Use {@link #setSupportSecondaryProgressTintList(ColorStateList)} instead.
*/
@Override
public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportSecondaryProgressTintList(tint);
}
/**
* @deprecated Use {@link #getSupportSecondaryProgressTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getSecondaryProgressTintMode() {
logRatingBarTintWarning();
return getSupportSecondaryProgressTintMode();
}
/**
* @deprecated Use {@link #setSupportSecondaryProgressTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportSecondaryProgressTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportProgressBackgroundTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getProgressBackgroundTintList() {
logRatingBarTintWarning();
return getSupportProgressBackgroundTintList();
}
/**
* @deprecated Use {@link #setSupportProgressBackgroundTintList(ColorStateList)} instead.
*/
@Override
public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportProgressBackgroundTintList(tint);
}
/**
* @deprecated Use {@link #getSupportProgressBackgroundTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getProgressBackgroundTintMode() {
logRatingBarTintWarning();
return getSupportProgressBackgroundTintMode();
}
/**
* @deprecated Use {@link #setSupportProgressBackgroundTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportProgressBackgroundTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportIndeterminateTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getIndeterminateTintList() {
logRatingBarTintWarning();
return getSupportIndeterminateTintList();
}
/**
* @deprecated Use {@link #setSupportIndeterminateTintList(ColorStateList)} instead.
*/
@Override
public void setIndeterminateTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportIndeterminateTintList(tint);
}
/**
* @deprecated Use {@link #getSupportIndeterminateTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getIndeterminateTintMode() {
logRatingBarTintWarning();
return getSupportIndeterminateTintMode();
}
/**
* @deprecated Use {@link #setSupportIndeterminateTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportIndeterminateTintMode(tintMode);
}
private void logRatingBarTintWarning() {
Log.w(TAG, "Non-support version of tint method called, this is error-prone and will crash" +
" below Lollipop if you are calling it as a method of RatingBar instead of" +
" MaterialRatingBar");
}
/**
* @see RatingBar#getProgressTintList()
*/
@Nullable
public ColorStateList getSupportProgressTintList() {
return mProgressTintInfo.mProgressTintList;
}
/**
* @see RatingBar#setProgressTintList(ColorStateList)
*/
public void setSupportProgressTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mProgressTintList = tint;
mProgressTintInfo.mHasProgressTintList = true;
applyPrimaryProgressTint();
}
/**
* @see RatingBar#getProgressTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportProgressTintMode() {
return mProgressTintInfo.mProgressTintMode;
}
/**
* @see RatingBar#setProgressTintMode(PorterDuff.Mode)
*/
public void setSupportProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mProgressTintMode = tintMode;
mProgressTintInfo.mHasProgressTintMode = true;
applyPrimaryProgressTint();
}
/**
* @see RatingBar#getSecondaryProgressTintList()
*/
@Nullable
public ColorStateList getSupportSecondaryProgressTintList() {
return mProgressTintInfo.mSecondaryProgressTintList;
}
/**
* @see RatingBar#setSecondaryProgressTintList(ColorStateList)
*/
public void setSupportSecondaryProgressTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mSecondaryProgressTintList = tint;
mProgressTintInfo.mHasSecondaryProgressTintList = true;
applySecondaryProgressTint();
}
/**
* @see RatingBar#getSecondaryProgressTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportSecondaryProgressTintMode() {
return mProgressTintInfo.mSecondaryProgressTintMode;
}
/**
* @see RatingBar#setSecondaryProgressTintMode(PorterDuff.Mode)
*/
public void setSupportSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mSecondaryProgressTintMode = tintMode;
mProgressTintInfo.mHasSecondaryProgressTintMode = true;
applySecondaryProgressTint();
}
/**
* @see RatingBar#getProgressBackgroundTintList()
*/
@Nullable
public ColorStateList getSupportProgressBackgroundTintList() {
return mProgressTintInfo.mProgressBackgroundTintList;
}
/**
* @see RatingBar#setProgressBackgroundTintList(ColorStateList)
*/
public void setSupportProgressBackgroundTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mProgressBackgroundTintList = tint;
mProgressTintInfo.mHasProgressBackgroundTintList = true;
applyProgressBackgroundTint();
}
/**
* @see RatingBar#getProgressBackgroundTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportProgressBackgroundTintMode() {
return mProgressTintInfo.mProgressBackgroundTintMode;
}
/**
* @see RatingBar#setProgressBackgroundTintMode(PorterDuff.Mode)
*/
public void setSupportProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mProgressBackgroundTintMode = tintMode;
mProgressTintInfo.mHasProgressBackgroundTintMode = true;
applyProgressBackgroundTint();
}
/**
* @see RatingBar#getIndeterminateTintList()
*/
@Nullable
public ColorStateList getSupportIndeterminateTintList() {
return mProgressTintInfo.mIndeterminateTintList;
}
/**
* @see RatingBar#setIndeterminateTintList(ColorStateList)
*/
public void setSupportIndeterminateTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mIndeterminateTintList = tint;
mProgressTintInfo.mHasIndeterminateTintList = true;
applyIndeterminateTint();
}
/**
* @see RatingBar#getIndeterminateTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportIndeterminateTintMode() {
return mProgressTintInfo.mIndeterminateTintMode;
}
/**
* @see RatingBar#setIndeterminateTintMode(PorterDuff.Mode)
*/
public void setSupportIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mIndeterminateTintMode = tintMode;
mProgressTintInfo.mHasIndeterminateTintMode = true;
applyIndeterminateTint();
}
private void applyProgressTints() {
if (getProgressDrawable() == null) {
return;
}
applyPrimaryProgressTint();
applyProgressBackgroundTint();
applySecondaryProgressTint();
}
private void applyPrimaryProgressTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasProgressTintList || mProgressTintInfo.mHasProgressTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.progress, true);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mProgressTintList,
mProgressTintInfo.mHasProgressTintList, mProgressTintInfo.mProgressTintMode,
mProgressTintInfo.mHasProgressTintMode);
}
}
}
private void applySecondaryProgressTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasSecondaryProgressTintList
|| mProgressTintInfo.mHasSecondaryProgressTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.secondaryProgress,
false);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mSecondaryProgressTintList,
mProgressTintInfo.mHasSecondaryProgressTintList,
mProgressTintInfo.mSecondaryProgressTintMode,
mProgressTintInfo.mHasSecondaryProgressTintMode);
}
}
}
private void applyProgressBackgroundTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasProgressBackgroundTintList
|| mProgressTintInfo.mHasProgressBackgroundTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.background, false);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mProgressBackgroundTintList,
mProgressTintInfo.mHasProgressBackgroundTintList,
mProgressTintInfo.mProgressBackgroundTintMode,
mProgressTintInfo.mHasProgressBackgroundTintMode);
}
}
}
private Drawable getTintTargetFromProgressDrawable(int layerId, boolean shouldFallback) {
Drawable progressDrawable = getProgressDrawable();
if (progressDrawable == null) {
return null;
}
progressDrawable.mutate();
Drawable layerDrawable = null;
if (progressDrawable instanceof LayerDrawable) {
layerDrawable = ((LayerDrawable) progressDrawable).findDrawableByLayerId(layerId);
}
if (layerDrawable == null && shouldFallback) {
layerDrawable = progressDrawable;
}
return layerDrawable;
}
private void applyIndeterminateTint() {
Drawable indeterminateDrawable = getIndeterminateDrawable();
if (indeterminateDrawable == null) {
return;
}
if (mProgressTintInfo.mHasIndeterminateTintList
|| mProgressTintInfo.mHasIndeterminateTintMode) {
indeterminateDrawable.mutate();
applyTintForDrawable(indeterminateDrawable, mProgressTintInfo.mIndeterminateTintList,
mProgressTintInfo.mHasIndeterminateTintList,
mProgressTintInfo.mIndeterminateTintMode,
mProgressTintInfo.mHasIndeterminateTintMode);
}
}
// Progress drawables in this library has already rewritten tint related methods for
// compatibility.
@SuppressLint("NewApi")
private void applyTintForDrawable(Drawable drawable, ColorStateList tintList,
boolean hasTintList, PorterDuff.Mode tintMode,
boolean hasTintMode) {
if (hasTintList || hasTintMode) {
if (hasTintList) {
if (drawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) drawable).setTintList(tintList);
} else {
logDrawableTintWarning();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable.setTintList(tintList);
}
}
}
if (hasTintMode) {
if (drawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) drawable).setTintMode(tintMode);
} else {
logDrawableTintWarning();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable.setTintMode(tintMode);
}
}
}
// The drawable (or one of its children) may not have been
// stateful before applying the tint, so let's try again.
if (drawable.isStateful()) {
drawable.setState(getDrawableState());
}
}
}
private void logDrawableTintWarning() {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
}
/**
* Get the listener that is listening for rating change events.
*
* @return The listener, may be null.
*/
public OnRatingChangeListener getOnRatingChangeListener() {
return mOnRatingChangeListener;
}
/**
* Sets the listener to be called when the rating changes.
*
* @param listener The listener.
*/
public void setOnRatingChangeListener(OnRatingChangeListener listener) {
mOnRatingChangeListener = listener;
}
@Override
public synchronized void setSecondaryProgress(int secondaryProgress) {
super.setSecondaryProgress(secondaryProgress);
// HACK: Check and call our listener here because this method is always called by
// updateSecondaryProgress() from onProgressRefresh().
float rating = getRating();
if (mOnRatingChangeListener != null && rating != mLastKnownRating) {
mOnRatingChangeListener.onRatingChanged(this, rating);
}
mLastKnownRating = rating;
}
/**
* A callback that notifies clients when the rating has been changed. This includes changes that
* were initiated by the user through a touch gesture or arrow key/trackball as well as changes
* that were initiated programmatically. This callback <strong>will</strong> be called
* continuously while the user is dragging, different from framework's
* {@link OnRatingBarChangeListener}.
*/
public interface OnRatingChangeListener {
/**
* Notification that the rating has changed. This <strong>will</strong> be called
* continuously while the user is dragging, different from framework's
* {@link OnRatingBarChangeListener}.
*
* @param ratingBar The RatingBar whose rating has changed.
* @param rating The current rating. This will be in the range 0..numStars.
*/
void onRatingChanged(MaterialRatingBarOld ratingBar, float rating);
}
private static class TintInfo {
public ColorStateList mProgressTintList;
public PorterDuff.Mode mProgressTintMode;
public boolean mHasProgressTintList;
public boolean mHasProgressTintMode;
public ColorStateList mSecondaryProgressTintList;
public PorterDuff.Mode mSecondaryProgressTintMode;
public boolean mHasSecondaryProgressTintList;
public boolean mHasSecondaryProgressTintMode;
public ColorStateList mProgressBackgroundTintList;
public PorterDuff.Mode mProgressBackgroundTintMode;
public boolean mHasProgressBackgroundTintList;
public boolean mHasProgressBackgroundTintMode;
public ColorStateList mIndeterminateTintList;
public PorterDuff.Mode mIndeterminateTintMode;
public boolean mHasIndeterminateTintList;
public boolean mHasIndeterminateTintMode;
}
}
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.view.Gravity;
import androidx.appcompat.content.res.AppCompatResources;
import cn.shangyu.gdxzExpert.R;
public class MaterialRatingDrawable extends LayerDrawable {
public MaterialRatingDrawable(Context context, boolean fillBackgroundStars) {
super(new Drawable[] {
createLayerDrawableWithTintAttrRes(fillBackgroundStars ?
R.drawable.noxing
: R.drawable.noxing, fillBackgroundStars ?
androidx.appcompat.R.attr.colorControlHighlight : androidx.appcompat.R.attr.colorControlNormal, context),
// fillBackgroundStars ? createClippedLayerDrawableWithTintColor(
// R.drawable.noxing, Color.TRANSPARENT, context)
// :
createClippedLayerDrawableWithTintAttrRes(
R.drawable.mrb_star_icon_black_36dp, androidx.appcompat.R.attr.colorControlActivated,
context),
createClippedLayerDrawableWithTintAttrRes(R.drawable.noxing,
androidx.appcompat.R.attr.colorControlActivated, context)
});
setId(0, android.R.id.background);
setId(1, android.R.id.secondaryProgress);
setId(2, android.R.id.progress);
}
private static Drawable createLayerDrawableWithTintColor(int tileRes, int tintColor,
Context context) {
TileDrawable drawable = new TileDrawable(AppCompatResources.getDrawable(context,
tileRes));
drawable.mutate();
//noinspection RedundantCast
((TintableDrawable) drawable).setTint(tintColor);
return drawable;
}
private static Drawable createLayerDrawableWithTintAttrRes(int tileRes, int tintAttrRes,
Context context) {
// int tintColor = ThemeUtils.getColorFromAttrRes(tintAttrRes, context);
int tintColor = Color.rgb(204,204,204);
return createLayerDrawableWithTintColor(tileRes, tintColor, context);
}
@SuppressLint("RtlHardcoded")
private static Drawable createClippedLayerDrawableWithTintColor(int tileResId, int tintColor,
Context context) {
return new ClipDrawableCompat(createLayerDrawableWithTintColor(tileResId, tintColor,
context), Gravity.LEFT, ClipDrawableCompat.HORIZONTAL);
}
@SuppressLint("RtlHardcoded")
private static Drawable createClippedLayerDrawableWithTintAttrRes(int tileResId,
int tintAttrRes,
Context context) {
return new ClipDrawableCompat(createLayerDrawableWithTintAttrRes(tileResId, tintAttrRes,
context), Gravity.LEFT, ClipDrawableCompat.HORIZONTAL);
}
@SuppressLint("RtlHardcoded")
private static Drawable createClippedTransparentLayerDrawable() {
return new ClipDrawableCompat(new TileDrawable(new ColorDrawable(Color.TRANSPARENT)),
Gravity.LEFT, ClipDrawableCompat.HORIZONTAL);
}
public float getTileRatio() {
Drawable drawable = getTileDrawableByLayerId(android.R.id.progress).getDrawable();
return (float) drawable.getIntrinsicWidth() / drawable.getIntrinsicHeight();
}
public void setStarCount(int count) {
getTileDrawableByLayerId(android.R.id.background).setTileCount(count);
getTileDrawableByLayerId(android.R.id.secondaryProgress).setTileCount(count);
getTileDrawableByLayerId(android.R.id.progress).setTileCount(count);
}
@SuppressLint("NewApi")
private TileDrawable getTileDrawableByLayerId(int id) {
Drawable layerDrawable = findDrawableByLayerId(id);
switch (id) {
case android.R.id.background:
return (TileDrawable) layerDrawable;
case android.R.id.secondaryProgress:
case android.R.id.progress: {
ClipDrawableCompat clipDrawable = (ClipDrawableCompat) layerDrawable;
return (TileDrawable) clipDrawable.getDrawable();
}
default:
// Should never reach here.
throw new RuntimeException();
}
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.content.Context;
import android.content.res.TypedArray;
public class ThemeUtils {
private ThemeUtils() {}
public static int getColorFromAttrRes(int attrRes, Context context) {
TypedArray a = context.obtainStyledAttributes(new int[] { attrRes });
try {
return a.getColor(0, 0);
} finally {
a.recycle();
}
}
public static float getFloatFromAttrRes(int attrRes, Context context) {
TypedArray a = context.obtainStyledAttributes(new int[] { attrRes });
try {
return a.getFloat(0, 0);
} finally {
a.recycle();
}
}
}
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
class TileDrawable extends BaseDrawable {
private Drawable mDrawable;
private int mTileCount = -1;
public TileDrawable(Drawable drawable) {
mDrawable = drawable;
}
public Drawable getDrawable() {
return mDrawable;
}
public int getTileCount() {
return mTileCount;
}
public void setTileCount(int tileCount) {
mTileCount = tileCount;
invalidateSelf();
}
@NonNull
@Override
public Drawable mutate() {
mDrawable = mDrawable.mutate();
return this;
}
@Override
protected void onDraw(Canvas canvas, int width, int height) {
mDrawable.setAlpha(mAlpha);
ColorFilter colorFilter = getColorFilterForDrawing();
if (colorFilter != null) {
mDrawable.setColorFilter(colorFilter);
}
int tileHeight = mDrawable.getIntrinsicHeight();
float scale = (float) height / tileHeight;
canvas.scale(scale, scale);
float scaledWidth = width / scale;
if (mTileCount < 0) {
int tileWidth = mDrawable.getIntrinsicWidth();
for (int x = 0; x < scaledWidth; x += tileWidth) {
mDrawable.setBounds(x, 0, x + tileWidth, tileHeight);
mDrawable.draw(canvas);
}
} else {
float tileWidth = scaledWidth / mTileCount;
for (int i = 0; i < mTileCount; ++i) {
int drawableWidth = mDrawable.getIntrinsicWidth();
float tileCenter = tileWidth * (i + 0.5f);
float drawableWidthHalf = (float) drawableWidth / 2;
mDrawable.setBounds(Math.round(tileCenter - drawableWidthHalf), 0,
Math.round(tileCenter + drawableWidthHalf), tileHeight);
mDrawable.draw(canvas);
}
}
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package cn.shangyu.gdxzExpert.widget.goodratingbar;
import android.content.res.ColorStateList;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* A {@code Drawable} that is tintable.
*/
public interface TintableDrawable {
/**
* Specifies tint color for this drawable.
* <p>
* A Drawable's drawing content will be blended together with its tint
* before it is drawn to the screen. This functions similarly to
* {@link Drawable#setColorFilter(int, PorterDuff.Mode)}.
* </p>
* <p>
* To clear the tint, pass {@code null} to
* {@link #setTintList(ColorStateList)}.
* </p>
* <p class="note"><strong>Note:</strong> Setting a color filter via
* {@link Drawable#setColorFilter(ColorFilter)} or
* {@link Drawable#setColorFilter(int, PorterDuff.Mode)} overrides tint.
* </p>
*
* @param tintColor Color to use for tinting this drawable
* @see #setTintList(ColorStateList)
* @see #setTintMode(PorterDuff.Mode)
*/
void setTint(@ColorInt int tintColor);
/**
* Specifies tint color for this drawable as a color state list.
* <p>
* A Drawable's drawing content will be blended together with its tint
* before it is drawn to the screen. This functions similarly to
* {@link Drawable#setColorFilter(int, PorterDuff.Mode)}.
* </p>
* <p class="note"><strong>Note:</strong> Setting a color filter via
* {@link Drawable#setColorFilter(ColorFilter)} or
* {@link Drawable#setColorFilter(int, PorterDuff.Mode)} overrides tint.
* </p>
*
* @param tint Color state list to use for tinting this drawable, or
* {@code null} to clear the tint
* @see #setTint(int)
* @see #setTintMode(PorterDuff.Mode)
*/
void setTintList(@Nullable ColorStateList tint);
/**
* Specifies a tint blending mode for this drawable.
* <p>
* Defines how this drawable's tint color should be blended into the drawable
* before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#SRC_IN}.
* </p>
* <p class="note"><strong>Note:</strong> Setting a color filter via
* {@link Drawable#setColorFilter(ColorFilter)} or
* {@link Drawable#setColorFilter(int, PorterDuff.Mode)} overrides tint.
* </p>
*
* @param tintMode A Porter-Duff blending mode
* @see #setTint(int)
* @see #setTintList(ColorStateList)
*/
void setTintMode(@NonNull PorterDuff.Mode tintMode);
}