Update CheckTextView
This commit is contained in:
8 files changed
+205
-164
No files matched your search
@@ -98,7 +98,7 @@ public class CategoryTable extends TableLayout implements View.OnLongClickListen
|
||||
boolean checked = ((CheckTextView) v).isChecked();
|
||||
for (CheckTextView option : mOptions) {
|
||||
if (option != v) {
|
||||
option.setChecked(!checked, false);
|
||||
option.setChecked(!checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,16 +132,16 @@ public class CategoryTable extends TableLayout implements View.OnLongClickListen
|
||||
* @param category target category
|
||||
*/
|
||||
public void setCategory(int category) {
|
||||
mDoujinshi.setChecked(!NumberUtils.int2boolean(category & EhConfig.DOUJINSHI), false);
|
||||
mManga.setChecked(!NumberUtils.int2boolean(category & EhConfig.MANGA), false);
|
||||
mArtistCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.ARTIST_CG), false);
|
||||
mGameCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.GAME_CG), false);
|
||||
mWestern.setChecked(!NumberUtils.int2boolean(category & EhConfig.WESTERN), false);
|
||||
mNonH.setChecked(!NumberUtils.int2boolean(category & EhConfig.NON_H), false);
|
||||
mImageSets.setChecked(!NumberUtils.int2boolean(category & EhConfig.IMAGE_SET), false);
|
||||
mCosplay.setChecked(!NumberUtils.int2boolean(category & EhConfig.COSPLAY), false);
|
||||
mAsianPorn.setChecked(!NumberUtils.int2boolean(category & EhConfig.ASIAN_PORN), false);
|
||||
mMisc.setChecked(!NumberUtils.int2boolean(category & EhConfig.MISC), false);
|
||||
mDoujinshi.setChecked(!NumberUtils.int2boolean(category & EhConfig.DOUJINSHI));
|
||||
mManga.setChecked(!NumberUtils.int2boolean(category & EhConfig.MANGA));
|
||||
mArtistCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.ARTIST_CG));
|
||||
mGameCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.GAME_CG));
|
||||
mWestern.setChecked(!NumberUtils.int2boolean(category & EhConfig.WESTERN));
|
||||
mNonH.setChecked(!NumberUtils.int2boolean(category & EhConfig.NON_H));
|
||||
mImageSets.setChecked(!NumberUtils.int2boolean(category & EhConfig.IMAGE_SET));
|
||||
mCosplay.setChecked(!NumberUtils.int2boolean(category & EhConfig.COSPLAY));
|
||||
mAsianPorn.setChecked(!NumberUtils.int2boolean(category & EhConfig.ASIAN_PORN));
|
||||
mMisc.setChecked(!NumberUtils.int2boolean(category & EhConfig.MISC));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,199 +16,226 @@
|
||||
|
||||
package com.hippo.widget;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.appcompat.widget.AppCompatCheckedTextView;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.hotspot.Hotspotable;
|
||||
import com.hippo.yorozuya.AnimationUtils;
|
||||
import com.hippo.yorozuya.MathUtils;
|
||||
import com.hippo.yorozuya.SimpleAnimatorListener;
|
||||
|
||||
public class CheckTextView extends AppCompatTextView implements OnClickListener, Hotspotable {
|
||||
public class CheckTextView extends AppCompatCheckedTextView implements View.OnClickListener {
|
||||
|
||||
private static final String STATE_KEY_SUPER = "super";
|
||||
private static final String STATE_KEY_CHECKED = "checked";
|
||||
private Drawable mForeground;
|
||||
|
||||
private static final long ANIMATION_DURATION = 200;
|
||||
Animator mAnimator;
|
||||
private final Animator.AnimatorListener mAnimatorListener = new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mAnimator = null;
|
||||
}
|
||||
};
|
||||
private int mMaskColor;
|
||||
private boolean mChecked = false;
|
||||
private boolean mPrepareAnimator = false;
|
||||
private Paint mPaint;
|
||||
private float mRadius = 0f;
|
||||
private float mX;
|
||||
private float mY;
|
||||
private float mMaxRadius;
|
||||
private final Rect mSelfBounds = new Rect();
|
||||
|
||||
private final Rect mOverlayBounds = new Rect();
|
||||
|
||||
private int mForegroundGravity = Gravity.FILL;
|
||||
|
||||
protected boolean mForegroundInPadding = true;
|
||||
|
||||
boolean mForegroundBoundsChanged = false;
|
||||
|
||||
public CheckTextView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CheckTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CheckTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init(context, attrs);
|
||||
public CheckTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
init(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckTextView);
|
||||
mMaskColor = a.getColor(R.styleable.CheckTextView_maskColor, Color.WHITE);
|
||||
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckTextView,
|
||||
defStyleAttr, 0);
|
||||
|
||||
mForegroundGravity = a.getInt(
|
||||
R.styleable.CheckTextView_android_foregroundGravity, mForegroundGravity);
|
||||
|
||||
Drawable d = a.getDrawable(R.styleable.CheckTextView_android_foreground);
|
||||
if (d != null) {
|
||||
setForeground(d);
|
||||
}
|
||||
|
||||
mForegroundInPadding = a.getBoolean(
|
||||
R.styleable.CheckTextView_foregroundInsidePadding, true);
|
||||
|
||||
a.recycle();
|
||||
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
|
||||
mPaint.setColor(mMaskColor);
|
||||
|
||||
setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHotspot(float x, float y) {
|
||||
mX = x;
|
||||
mY = y;
|
||||
mMaxRadius = MathUtils.coverageRadius(getWidth(), getHeight(), x, y);
|
||||
/**
|
||||
* Describes how the foreground is positioned.
|
||||
*
|
||||
* @return foreground gravity.
|
||||
* @see #setForegroundGravity(int)
|
||||
*/
|
||||
public int getForegroundGravity() {
|
||||
return mForegroundGravity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawableHotspotChanged(float x, float y) {
|
||||
super.drawableHotspotChanged(x, y);
|
||||
|
||||
mX = x;
|
||||
mY = y;
|
||||
mMaxRadius = MathUtils.coverageRadius(getWidth(), getHeight(), x, y);
|
||||
}
|
||||
|
||||
public float getRadius() {
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
public void setRadius(float radius) {
|
||||
float bigger = Math.max(mRadius, radius);
|
||||
mRadius = radius;
|
||||
invalidate((int) (mX - bigger), (int) (mY - bigger), (int) (mX + bigger), (int) (mY + bigger));
|
||||
}
|
||||
|
||||
public void prepareAnimations() {
|
||||
mPrepareAnimator = true;
|
||||
}
|
||||
|
||||
private void createAnimations() {
|
||||
float startRadius;
|
||||
float endRadius;
|
||||
Interpolator interpolator;
|
||||
if (mChecked) {
|
||||
startRadius = 0;
|
||||
endRadius = mMaxRadius;
|
||||
interpolator = AnimationUtils.FAST_SLOW_INTERPOLATOR;
|
||||
} else {
|
||||
startRadius = mMaxRadius;
|
||||
endRadius = 0;
|
||||
interpolator = AnimationUtils.SLOW_FAST_INTERPOLATOR;
|
||||
}
|
||||
mRadius = startRadius;
|
||||
|
||||
final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radius", startRadius, endRadius);
|
||||
radiusAnim.setDuration(ANIMATION_DURATION);
|
||||
radiusAnim.setInterpolator(interpolator);
|
||||
radiusAnim.addListener(mAnimatorListener);
|
||||
radiusAnim.start();
|
||||
mAnimator = radiusAnim;
|
||||
}
|
||||
|
||||
private void cancelAnimations() {
|
||||
if (mAnimator != null) {
|
||||
mAnimator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setChecked(!mChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(@NonNull Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (mPrepareAnimator) {
|
||||
mPrepareAnimator = false;
|
||||
cancelAnimations();
|
||||
createAnimations();
|
||||
}
|
||||
|
||||
if (mAnimator != null) {
|
||||
canvas.drawCircle(mX, mY, mRadius, mPaint);
|
||||
} else {
|
||||
if (mChecked) {
|
||||
canvas.drawColor(mMaskColor);
|
||||
/**
|
||||
* Describes how the foreground is positioned. Defaults to START and TOP.
|
||||
*
|
||||
* @param foregroundGravity See {@link android.view.Gravity}
|
||||
* @see #getForegroundGravity()
|
||||
*/
|
||||
public void setForegroundGravity(int foregroundGravity) {
|
||||
if (mForegroundGravity != foregroundGravity) {
|
||||
if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
|
||||
foregroundGravity |= Gravity.START;
|
||||
}
|
||||
|
||||
if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
|
||||
foregroundGravity |= Gravity.TOP;
|
||||
}
|
||||
|
||||
mForegroundGravity = foregroundGravity;
|
||||
|
||||
if (mForegroundGravity == Gravity.FILL && mForeground != null) {
|
||||
Rect padding = new Rect();
|
||||
mForeground.getPadding(padding);
|
||||
}
|
||||
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean verifyDrawable(@NonNull Drawable who) {
|
||||
return super.verifyDrawable(who) || (who == mForeground);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpDrawablesToCurrentState() {
|
||||
super.jumpDrawablesToCurrentState();
|
||||
if (mForeground != null) {
|
||||
mForeground.jumpToCurrentState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged() {
|
||||
super.drawableStateChanged();
|
||||
if (mForeground != null && mForeground.isStateful()) {
|
||||
mForeground.setState(getDrawableState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the checked state of this CheckTextView.
|
||||
* Supply a Drawable that is to be rendered on top of all of the child
|
||||
* views in the frame layout. Any padding in the Drawable will be taken
|
||||
* into account by ensuring that the children are inset to be placed
|
||||
* inside of the padding area.
|
||||
*
|
||||
* @param checked checked true to check the CheckTextView, false to uncheck it
|
||||
* @param animation true for show animation
|
||||
* @param drawable The Drawable to be drawn on top of the children.
|
||||
*/
|
||||
public void setChecked(boolean checked, boolean animation) {
|
||||
if (mChecked != checked) {
|
||||
mChecked = checked;
|
||||
|
||||
if (animation) {
|
||||
prepareAnimations();
|
||||
public void setForeground(Drawable drawable) {
|
||||
if (mForeground != drawable) {
|
||||
if (mForeground != null) {
|
||||
mForeground.setCallback(null);
|
||||
unscheduleDrawable(mForeground);
|
||||
}
|
||||
|
||||
mForeground = drawable;
|
||||
|
||||
if (drawable != null) {
|
||||
setWillNotDraw(false);
|
||||
drawable.setCallback(this);
|
||||
if (drawable.isStateful()) {
|
||||
drawable.setState(getDrawableState());
|
||||
}
|
||||
if (mForegroundGravity == Gravity.FILL) {
|
||||
Rect padding = new Rect();
|
||||
drawable.getPadding(padding);
|
||||
}
|
||||
} else {
|
||||
setWillNotDraw(true);
|
||||
}
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the checked state of it.
|
||||
* Returns the drawable used as the foreground of this FrameLayout. The
|
||||
* foreground drawable, if non-null, is always drawn on top of the children.
|
||||
*
|
||||
* @return true is it is checked
|
||||
* @return A Drawable or null if no foreground was set.
|
||||
*/
|
||||
public boolean isChecked() {
|
||||
return mChecked;
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
setChecked(checked, true);
|
||||
public Drawable getForeground() {
|
||||
return mForeground;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
final Bundle state = new Bundle();
|
||||
state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState());
|
||||
state.putBoolean(STATE_KEY_CHECKED, mChecked);
|
||||
return state;
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
mForegroundBoundsChanged |= changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
final Bundle savedState = (Bundle) state;
|
||||
super.onRestoreInstanceState(savedState.getParcelable(STATE_KEY_SUPER));
|
||||
setChecked(savedState.getBoolean(STATE_KEY_CHECKED), false);
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
mForegroundBoundsChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
|
||||
if (mForeground != null) {
|
||||
final Drawable foreground = mForeground;
|
||||
|
||||
if (mForegroundBoundsChanged) {
|
||||
mForegroundBoundsChanged = false;
|
||||
final Rect selfBounds = mSelfBounds;
|
||||
final Rect overlayBounds = mOverlayBounds;
|
||||
|
||||
final int w = getRight() - getLeft();
|
||||
final int h = getBottom() - getTop();
|
||||
|
||||
if (mForegroundInPadding) {
|
||||
selfBounds.set(0, 0, w, h);
|
||||
} else {
|
||||
selfBounds.set(getPaddingLeft(), getPaddingTop(),
|
||||
w - getPaddingRight(), h - getPaddingBottom());
|
||||
}
|
||||
|
||||
Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
|
||||
foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
|
||||
foreground.setBounds(overlayBounds);
|
||||
}
|
||||
|
||||
foreground.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawableHotspotChanged(float x, float y) {
|
||||
super.drawableHotspotChanged(x, y);
|
||||
if (mForeground != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
mForeground.setHotspot(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setChecked(!isChecked());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user