33
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
+668
@@ -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;
|
||||
}
|
||||
}
|
||||
+108
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user