feat: 优化代码

pull/165/head
kunfei 5 years ago
parent a0463171c0
commit 6f260e4f1d
  1. 119
      app/src/main/java/io/legado/app/ui/widget/SearchView.java
  2. 113
      app/src/main/java/io/legado/app/ui/widget/SearchView.kt
  3. 195
      app/src/main/java/io/legado/app/ui/widget/ShadowLayout.java
  4. 185
      app/src/main/java/io/legado/app/ui/widget/ShadowLayout.kt

@ -1,119 +0,0 @@
package io.legado.app.ui.widget;
import android.app.SearchableInfo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.legado.app.R;
public class SearchView extends androidx.appcompat.widget.SearchView {
private Drawable mSearchHintIcon = null;
private TextView textView = null;
public SearchView(Context context) {
this(context, null);
}
public SearchView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SearchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
try {
if (textView == null) {
textView = (TextView) this.findViewById(androidx.appcompat.R.id.search_src_text);
mSearchHintIcon = this.getContext().getDrawable(R.drawable.ic_search_hint);
updateQueryHint();
}
// 改变字体
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
textView.setGravity(Gravity.CENTER_VERTICAL);
} catch (Exception e) {
e.printStackTrace();
}
}
private CharSequence getDecoratedHint(CharSequence hintText) {
// If the field is always expanded or we don't have a search hint icon,
// then don't add the search icon to the hint.
if (mSearchHintIcon == null) {
return hintText;
}
final int textSize = (int) (textView.getTextSize() * 0.8);
mSearchHintIcon.setBounds(0, 0, textSize, textSize);
final SpannableStringBuilder ssb = new SpannableStringBuilder(" ");
ssb.setSpan(new CenteredImageSpan(mSearchHintIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append(hintText);
return ssb;
}
private void updateQueryHint() {
if (textView != null) {
final CharSequence hint = getQueryHint();
textView.setHint(getDecoratedHint(hint == null ? "" : hint));
}
}
@Override
public void setIconifiedByDefault(boolean iconified) {
super.setIconifiedByDefault(iconified);
updateQueryHint();
}
@Override
public void setSearchableInfo(SearchableInfo searchable) {
super.setSearchableInfo(searchable);
if (searchable != null)
updateQueryHint();
}
@Override
public void setQueryHint(@Nullable CharSequence hint) {
super.setQueryHint(hint);
updateQueryHint();
}
}
class CenteredImageSpan extends ImageSpan {
public CenteredImageSpan(final Drawable drawable) {
super(drawable);
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text,
int start, int end, float x,
int top, int y, int bottom, @NonNull Paint paint) {
// image to draw
Drawable b = getDrawable();
// font metrics of text to be replaced
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int transY = (y + fm.descent + y + fm.ascent) / 2
- b.getBounds().bottom / 2;
canvas.save();
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
}

@ -0,0 +1,113 @@
package io.legado.app.ui.widget
import android.app.SearchableInfo
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ImageSpan
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.widget.TextView
import androidx.appcompat.widget.SearchView
import io.legado.app.R
class SearchView : SearchView {
private var mSearchHintIcon: Drawable? = null
private var textView: TextView? = null
constructor(
context: Context?,
attrs: AttributeSet? = null
) : super(context, attrs)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int
) : super(context, attrs, defStyleAttr)
override fun onLayout(
changed: Boolean,
left: Int,
top: Int,
right: Int,
bottom: Int
) {
super.onLayout(changed, left, top, right, bottom)
try {
if (textView == null) {
textView =
findViewById<View>(androidx.appcompat.R.id.search_src_text) as TextView
mSearchHintIcon = this.context.getDrawable(R.drawable.ic_search_hint)
updateQueryHint()
}
// 改变字体
textView!!.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
textView!!.gravity = Gravity.CENTER_VERTICAL
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun getDecoratedHint(hintText: CharSequence): CharSequence {
// If the field is always expanded or we don't have a search hint icon,
// then don't add the search icon to the hint.
if (mSearchHintIcon == null) {
return hintText
}
val textSize = (textView!!.textSize * 0.8).toInt()
mSearchHintIcon!!.setBounds(0, 0, textSize, textSize)
val ssb = SpannableStringBuilder(" ")
ssb.setSpan(CenteredImageSpan(mSearchHintIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
ssb.append(hintText)
return ssb
}
private fun updateQueryHint() {
if (textView != null) {
val hint = queryHint
textView!!.hint = getDecoratedHint(hint ?: "")
}
}
override fun setIconifiedByDefault(iconified: Boolean) {
super.setIconifiedByDefault(iconified)
updateQueryHint()
}
override fun setSearchableInfo(searchable: SearchableInfo?) {
super.setSearchableInfo(searchable)
searchable?.let {
updateQueryHint()
}
}
override fun setQueryHint(hint: CharSequence?) {
super.setQueryHint(hint)
updateQueryHint()
}
}
internal class CenteredImageSpan(drawable: Drawable?) : ImageSpan(drawable!!) {
override fun draw(
canvas: Canvas, text: CharSequence,
start: Int, end: Int, x: Float,
top: Int, y: Int, bottom: Int, paint: Paint
) {
// image to draw
val b = drawable
// font metrics of text to be replaced
val fm = paint.fontMetricsInt
val transY = ((y + fm.descent + y + fm.ascent) / 2
- b.bounds.bottom / 2)
canvas.save()
canvas.translate(x, transY.toFloat())
b.draw(canvas)
canvas.restore()
}
}

@ -1,195 +0,0 @@
package io.legado.app.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.RelativeLayout;
import io.legado.app.R;
/**
* ShadowLayout.java
* <p>
* Created by lijiankun on 17/8/11.
*/
public class ShadowLayout extends RelativeLayout {
public static final int ALL = 0x1111;
public static final int LEFT = 0x0001;
public static final int TOP = 0x0010;
public static final int RIGHT = 0x0100;
public static final int BOTTOM = 0x1000;
public static final int SHAPE_RECTANGLE = 0x0001;
public static final int SHAPE_OVAL = 0x0010;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mRectF = new RectF();
/**
* 阴影的颜色
*/
private int mShadowColor = Color.TRANSPARENT;
/**
* 阴影的大小范围
*/
private float mShadowRadius = 0;
/**
* 阴影 x 轴的偏移量
*/
private float mShadowDx = 0;
/**
* 阴影 y 轴的偏移量
*/
private float mShadowDy = 0;
/**
* 阴影显示的边界
*/
private int mShadowSide = ALL;
/**
* 阴影的形状圆形/矩形
*/
private int mShadowShape = SHAPE_RECTANGLE;
public ShadowLayout(Context context) {
this(context, null);
}
public ShadowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ShadowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
float effect = mShadowRadius + dip2px(5);
float rectLeft = 0;
float rectTop = 0;
float rectRight = this.getMeasuredWidth();
float rectBottom = this.getMeasuredHeight();
int paddingLeft = 0;
int paddingTop = 0;
int paddingRight = 0;
int paddingBottom = 0;
this.getWidth();
if ((mShadowSide & LEFT) == LEFT) {
rectLeft = effect;
paddingLeft = (int) effect;
}
if ((mShadowSide & TOP) == TOP) {
rectTop = effect;
paddingTop = (int) effect;
}
if ((mShadowSide & RIGHT) == RIGHT) {
rectRight = this.getMeasuredWidth() - effect;
paddingRight = (int) effect;
}
if ((mShadowSide & BOTTOM) == BOTTOM) {
rectBottom = this.getMeasuredHeight() - effect;
paddingBottom = (int) effect;
}
if (mShadowDy != 0.0f) {
rectBottom = rectBottom - mShadowDy;
paddingBottom = paddingBottom + (int) mShadowDy;
}
if (mShadowDx != 0.0f) {
rectRight = rectRight - mShadowDx;
paddingRight = paddingRight + (int) mShadowDx;
}
mRectF.left = rectLeft;
mRectF.top = rectTop;
mRectF.right = rectRight;
mRectF.bottom = rectBottom;
this.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
/**
* 真正绘制阴影的方法
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setUpShadowPaint();
if (mShadowShape == SHAPE_RECTANGLE) {
canvas.drawRect(mRectF, mPaint);
} else if (mShadowShape == SHAPE_OVAL) {
canvas.drawCircle(mRectF.centerX(), mRectF.centerY(), Math.min(mRectF.width(), mRectF.height()) / 2, mPaint);
}
}
public void setShadowColor(int shadowColor) {
mShadowColor = shadowColor;
requestLayout();
postInvalidate();
}
public void setShadowRadius(float shadowRadius) {
mShadowRadius = shadowRadius;
requestLayout();
postInvalidate();
}
/**
* 读取设置的阴影的属性
*
* @param attrs 从其中获取设置的值
*/
private void init(AttributeSet attrs) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null); // 关闭硬件加速
this.setWillNotDraw(false); // 调用此方法后,才会执行 onDraw(Canvas) 方法
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ShadowLayout);
if (typedArray != null) {
mShadowColor = typedArray.getColor(R.styleable.ShadowLayout_shadowColor,
getContext().getResources().getColor(android.R.color.black));
mShadowRadius = typedArray.getDimension(R.styleable.ShadowLayout_shadowRadius, dip2px(0));
mShadowDx = typedArray.getDimension(R.styleable.ShadowLayout_shadowDx, dip2px(0));
mShadowDy = typedArray.getDimension(R.styleable.ShadowLayout_shadowDy, dip2px(0));
mShadowSide = typedArray.getInt(R.styleable.ShadowLayout_shadowSide, ALL);
mShadowShape = typedArray.getInt(R.styleable.ShadowLayout_shadowShape, SHAPE_RECTANGLE);
typedArray.recycle();
}
setUpShadowPaint();
}
private void setUpShadowPaint() {
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.TRANSPARENT);
mPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
}
/**
* dip2px dp 值转 px
*
* @param dpValue dp
* @return px
*/
private float dip2px(float dpValue) {
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
float scale = dm.density;
return (dpValue * scale + 0.5F);
}
}

@ -0,0 +1,185 @@
package io.legado.app.ui.widget
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import android.widget.RelativeLayout
import io.legado.app.R
import io.legado.app.utils.getCompatColor
/**
* ShadowLayout.java
*
*
* Created by lijiankun on 17/8/11.
*/
class ShadowLayout(
context: Context,
attrs: AttributeSet? = null
) : RelativeLayout(context, attrs) {
private val mPaint =
Paint(Paint.ANTI_ALIAS_FLAG)
private val mRectF = RectF()
/**
* 阴影的颜色
*/
private var mShadowColor = Color.TRANSPARENT
/**
* 阴影的大小范围
*/
private var mShadowRadius = 0f
/**
* 阴影 x 轴的偏移量
*/
private var mShadowDx = 0f
/**
* 阴影 y 轴的偏移量
*/
private var mShadowDy = 0f
/**
* 阴影显示的边界
*/
private var mShadowSide = ALL
/**
* 阴影的形状圆形/矩形
*/
private var mShadowShape = SHAPE_RECTANGLE
init {
setLayerType(View.LAYER_TYPE_SOFTWARE, null) // 关闭硬件加速
setWillNotDraw(false) // 调用此方法后,才会执行 onDraw(Canvas) 方法
val typedArray =
context.obtainStyledAttributes(attrs, R.styleable.ShadowLayout)
mShadowColor = typedArray.getColor(
R.styleable.ShadowLayout_shadowColor,
context.getCompatColor(android.R.color.black)
)
mShadowRadius =
typedArray.getDimension(R.styleable.ShadowLayout_shadowRadius, dip2px(0f))
mShadowDx = typedArray.getDimension(R.styleable.ShadowLayout_shadowDx, dip2px(0f))
mShadowDy = typedArray.getDimension(R.styleable.ShadowLayout_shadowDy, dip2px(0f))
mShadowSide =
typedArray.getInt(R.styleable.ShadowLayout_shadowSide, ALL)
mShadowShape = typedArray.getInt(
R.styleable.ShadowLayout_shadowShape,
SHAPE_RECTANGLE
)
typedArray.recycle()
setUpShadowPaint()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val effect = mShadowRadius + dip2px(5f)
var rectLeft = 0f
var rectTop = 0f
var rectRight = this.measuredWidth.toFloat()
var rectBottom = this.measuredHeight.toFloat()
var paddingLeft = 0
var paddingTop = 0
var paddingRight = 0
var paddingBottom = 0
this.width
if (mShadowSide and LEFT == LEFT) {
rectLeft = effect
paddingLeft = effect.toInt()
}
if (mShadowSide and TOP == TOP) {
rectTop = effect
paddingTop = effect.toInt()
}
if (mShadowSide and RIGHT == RIGHT) {
rectRight = this.measuredWidth - effect
paddingRight = effect.toInt()
}
if (mShadowSide and BOTTOM == BOTTOM) {
rectBottom = this.measuredHeight - effect
paddingBottom = effect.toInt()
}
if (mShadowDy != 0.0f) {
rectBottom -= mShadowDy
paddingBottom += mShadowDy.toInt()
}
if (mShadowDx != 0.0f) {
rectRight -= mShadowDx
paddingRight += mShadowDx.toInt()
}
mRectF.left = rectLeft
mRectF.top = rectTop
mRectF.right = rectRight
mRectF.bottom = rectBottom
setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom)
}
/**
* 真正绘制阴影的方法
*/
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
setUpShadowPaint()
if (mShadowShape == SHAPE_RECTANGLE) {
canvas.drawRect(mRectF, mPaint)
} else if (mShadowShape == SHAPE_OVAL) {
canvas.drawCircle(
mRectF.centerX(),
mRectF.centerY(),
mRectF.width().coerceAtMost(mRectF.height()) / 2,
mPaint
)
}
}
fun setShadowColor(shadowColor: Int) {
mShadowColor = shadowColor
requestLayout()
postInvalidate()
}
fun setShadowRadius(shadowRadius: Float) {
mShadowRadius = shadowRadius
requestLayout()
postInvalidate()
}
private fun setUpShadowPaint() {
mPaint.reset()
mPaint.isAntiAlias = true
mPaint.color = Color.TRANSPARENT
mPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor)
}
/**
* dip2px dp 值转 px
*
* @param dpValue dp
* @return px
*/
private fun dip2px(dpValue: Float): Float {
val dm = context.resources.displayMetrics
val scale = dm.density
return dpValue * scale + 0.5f
}
companion object {
const val ALL = 0x1111
const val LEFT = 0x0001
const val TOP = 0x0010
const val RIGHT = 0x0100
const val BOTTOM = 0x1000
const val SHAPE_RECTANGLE = 0x0001
const val SHAPE_OVAL = 0x0010
}
}
Loading…
Cancel
Save