From 84073b006927b73884f74b7c4832d2be073083cf Mon Sep 17 00:00:00 2001 From: yangyxd Date: Wed, 18 Mar 2020 14:31:04 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B9=9D=E5=AE=AB=E6=A0=BC,?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/ui/book/search/SearchActivity.kt | 2 + .../io/legado/app/ui/widget/SearchView.java | 119 +++++++++++ .../io/legado/app/ui/widget/ShadowLayout.java | 195 ++++++++++++++++++ app/src/main/res/drawable/ic_help.xml | 27 ++- app/src/main/res/drawable/ic_search_hint.xml | 8 + app/src/main/res/layout/activity_main.xml | 2 +- .../main/res/layout/item_bookshelf_grid.xml | 90 ++++---- app/src/main/res/layout/view_search.xml | 11 +- app/src/main/res/values/attrs.xml | 13 ++ 9 files changed, 408 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/SearchView.java create mode 100644 app/src/main/java/io/legado/app/ui/widget/ShadowLayout.java create mode 100644 app/src/main/res/drawable/ic_search_hint.xml diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 8de6a489c..4373dd41a 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.book.search import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import androidx.appcompat.widget.SearchView @@ -128,6 +129,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se openOrCloseHistory(hasFocus) } } + openOrCloseHistory(true) } private fun initRecyclerView() { diff --git a/app/src/main/java/io/legado/app/ui/widget/SearchView.java b/app/src/main/java/io/legado/app/ui/widget/SearchView.java new file mode 100644 index 000000000..3ee0bd69b --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/SearchView.java @@ -0,0 +1,119 @@ +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(); + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/ShadowLayout.java b/app/src/main/java/io/legado/app/ui/widget/ShadowLayout.java new file mode 100644 index 000000000..4ef6ffd2e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/ShadowLayout.java @@ -0,0 +1,195 @@ +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 + *

+ * 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); + } +} diff --git a/app/src/main/res/drawable/ic_help.xml b/app/src/main/res/drawable/ic_help.xml index 931a86bf6..d5ecd8235 100644 --- a/app/src/main/res/drawable/ic_help.xml +++ b/app/src/main/res/drawable/ic_help.xml @@ -1,15 +1,12 @@ - - - - - + + + + diff --git a/app/src/main/res/drawable/ic_search_hint.xml b/app/src/main/res/drawable/ic_search_hint.xml new file mode 100644 index 000000000..42de64c26 --- /dev/null +++ b/app/src/main/res/drawable/ic_search_hint.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 77ed85415..701dea9b5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -7,7 +7,7 @@ + android:paddingTop="2dp" + android:paddingRight="10dp" + android:paddingLeft="10dp"> - + app:shadowColor="#16000000" + app:shadowShape="rectangle" + app:shadowDx="1dp" + app:shadowDy="3dp" + app:shadowRadius="4dp" + app:shadowSide="all"> - + + + + - - + android:layout_gravity="right" + android:layout_margin="5dp" + android:includeFontPadding="false" + app:layout_constraintTop_toTopOf="@+id/bg_cover" + app:layout_constraintRight_toRightOf="@+id/bg_cover" + tools:ignore="RtlHardcoded" /> - - + \ No newline at end of file diff --git a/app/src/main/res/layout/view_search.xml b/app/src/main/res/layout/view_search.xml index 9b1d48efd..b1809c534 100644 --- a/app/src/main/res/layout/view_search.xml +++ b/app/src/main/res/layout/view_search.xml @@ -1,15 +1,18 @@ - \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index d5a4d11e1..9e920088b 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -173,4 +173,17 @@ + + + + + + + + + + + + + \ No newline at end of file