parent
d34f7ea007
commit
84073b0069
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* <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); |
||||||
|
} |
||||||
|
} |
@ -1,15 +1,12 @@ |
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
android:width="200dp" |
android:width="22dp" |
||||||
android:height="200dp" |
android:height="22dp" |
||||||
android:viewportWidth="200" |
android:viewportWidth="1024" |
||||||
android:viewportHeight="200"> |
android:viewportHeight="1024"> |
||||||
<path |
<path |
||||||
android:fillColor="#FF000000" |
android:fillColor="#8F000000" |
||||||
android:pathData="M100.1,181.4c-10.9,0 -21.5,-2.1 -31.4,-6.3c-9.6,-4.1 -18.2,-9.9 -25.7,-17.3s-13.2,-16 -17.3,-25.7c-4.2,-10 -6.3,-20.5 -6.3,-31.4c0,-10.9 2.1,-21.5 6.3,-31.4C29.8,59.7 35.6,51 43,43.6c7.4,-7.4 16,-13.2 25.7,-17.3c10,-4.2 20.5,-6.3 31.4,-6.3s21.5,2.1 31.4,6.3c9.6,4.1 18.2,9.9 25.7,17.3c7.4,7.4 13.2,16 17.3,25.7c4.2,10 6.3,20.5 6.3,31.4s-2.1,21.5 -6.3,31.4c-4.1,9.6 -9.9,18.2 -17.3,25.7c-7.4,7.4 -16,13.2 -25.7,17.3C121.6,179.3 111,181.4 100.1,181.4zM100.1,31.6C62,31.6 31,62.6 31,100.7c0,38.1 31,69.2 69.2,69.2s69.2,-31 69.2,-69.2C169.3,62.6 138.2,31.6 100.1,31.6L100.1,31.6z" /> |
android:pathData="M474.84,721.55c0,21.68 17.55,38.71 38.71,38.71 21.68,0 38.71,-17.55 38.71,-38.71 0,-13.94 -7.23,-26.84 -19.61,-33.55 -11.87,-6.71 -26.84,-6.71 -38.71,0s-19.1,19.61 -19.1,33.55zM474.84,721.55M509.94,263.74C433.55,263.74 371.61,325.16 371.61,401.03c0,17.03 13.94,31.48 31.48,31.48 17.03,0 30.97,-13.94 31.48,-31.48 0,-41.81 33.03,-74.32 75.87,-74.32 41.81,0 75.87,34.06 75.87,76.39 0,16 -22.71,38.71 -42.84,58.84 -29.94,29.94 -64,64 -64,109.94v45.42c0.52,16.52 14.45,29.94 31.48,29.94s30.45,-13.42 30.97,-29.94v-45.42c0,-19.61 24.26,-44.39 45.94,-65.55 29.94,-29.94 60.9,-60.9 60.9,-102.71 -1.03,-77.42 -62.97,-139.87 -138.84,-139.87zM509.94,263.74"/> |
||||||
<path |
<path |
||||||
android:fillColor="#FF000000" |
android:fillColor="#8F000000" |
||||||
android:pathData="M114.1,78.8c0,-7.1 -4.2,-12.9 -14,-12.9c-6.3,0 -12.2,3.1 -18,9.2l-3.5,-3.3C84.8,65.5 91,61 100.6,61c12.1,0 19.2,7.3 19.2,17.4c0,15.1 -22.3,19 -19,34.4h-5.3C92,95.9 114.1,90.9 114.1,78.8zM98.5,122.6c3.3,0 6.4,2.3 6.4,6.4c0,4.2 -3.1,6.5 -6.4,6.5c-3.4,0 -6.4,-2.3 -6.4,-6.5C92,125 95.1,122.6 98.5,122.6z" /> |
android:pathData="M512,157.42c195.61,0 354.06,158.97 354.58,354.58 0,195.61 -158.97,354.58 -354.58,354.58s-354.58,-158.97 -354.58,-354.58 159.48,-354.58 354.58,-354.58m0,-68.65c-233.81,0 -423.23,189.42 -423.23,423.23s189.42,423.23 423.23,423.23 423.23,-189.42 423.23,-423.23 -189.42,-423.23 -423.23,-423.23zM512,88.77"/> |
||||||
<path |
</vector> |
||||||
android:fillColor="#FF000000" |
|
||||||
android:pathData="M98.5,138.1c-5.1,0 -8.9,-3.8 -8.9,-9c0,-5.1 3.7,-8.9 8.9,-8.9c5.1,0 8.9,3.8 8.9,8.9C107.4,134.9 102.8,138.1 98.5,138.1zM98.5,125.1c-1.8,0 -4,1 -4,4c0,3 2.2,4.1 4,4.1c2,0 4,-1.3 4,-4.1C102.5,126.3 100.4,125.1 98.5,125.1zM103.8,115.2H93.6l-0.4,-1.9c-1,-4.9 -0.2,-9.4 2.4,-13.6c2.2,-3.6 5.3,-6.5 8.3,-9.3c4.2,-3.9 7.9,-7.4 7.9,-11.6c0,-3.9 -1.5,-10.4 -11.5,-10.4c-5.5,0 -10.8,2.8 -16.2,8.4l-1.7,1.8l-7.1,-6.7l1.7,-1.8c6.8,-6.9 13.4,-11.5 23.7,-11.5c13,0 21.7,8 21.7,19.8c0,8.3 -5.7,13.6 -10.8,18.2c-5.2,4.8 -9.7,9 -8.3,15.6L103.8,115.2L103.8,115.2zM97.7,110.3h0.4c-0.3,-7.7 5.2,-12.8 10.1,-17.3c4.7,-4.4 9.2,-8.5 9.2,-14.6c0,-9.1 -6.6,-14.9 -16.8,-14.9c-0.1,0 -0.2,0 -0.3,0c10,0.1 16.2,5.9 16.2,15.3c0,6.3 -4.8,10.8 -9.4,15.2C102,98.7 97.1,103.3 97.7,110.3L97.7,110.3zM95.2,64c-3,0.7 -5.7,1.9 -8.2,3.7C89.7,65.9 92.4,64.7 95.2,64z" /> |
|
||||||
</vector> |
|
||||||
|
@ -0,0 +1,8 @@ |
|||||||
|
<vector android:height="8dp" |
||||||
|
android:viewportHeight="1024" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:width="8dp" |
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<path android:fillColor="#c0c0c0" android:pathData="M462.43,894.32c-242.22,0 -439.3,-197.03 -439.3,-439.3S220.16,15.78 462.43,15.78s439.3,197.03 439.3,439.3 -197.07,439.25 -439.3,439.25zM462.43,62.32c-216.58,0 -392.75,176.17 -392.75,392.75s176.17,392.75 392.75,392.75c216.53,0 392.75,-176.17 392.75,-392.75s-176.22,-392.75 -392.75,-392.75z"/> |
||||||
|
<path android:fillColor="#c0c0c0" android:pathData="M977.64,991.98a23.37,23.37 0,0 1,-16.48 -6.8l-211.22,-211.22a23.27,23.27 0,0 1,32.91 -32.91l211.22,211.22a23.27,23.27 0,0 1,-16.43 39.7z"/> |
||||||
|
</vector> |
@ -1,15 +1,18 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||||
<androidx.appcompat.widget.SearchView |
<io.legado.app.ui.widget.SearchView |
||||||
xmlns:android="http://schemas.android.com/apk/res/android" |
xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
android:id="@+id/search_view" |
android:id="@+id/search_view" |
||||||
android:theme="?attr/actionBarStyle" |
android:theme="?attr/actionBarStyle" |
||||||
android:background="@drawable/bg_searchview" |
android:background="@drawable/bg_searchview" |
||||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||||
android:layout_height="34dp" |
android:layout_height="30dp" |
||||||
android:layout_marginTop="8dp" |
android:layout_marginTop="10dp" |
||||||
android:layout_marginBottom="8dp" |
android:layout_marginBottom="10dp" |
||||||
android:imeOptions="actionSearch" |
android:imeOptions="actionSearch" |
||||||
|
android:focusable="false" |
||||||
app:queryBackground="@null" |
app:queryBackground="@null" |
||||||
app:submitBackground="@null" |
app:submitBackground="@null" |
||||||
|
app:searchHintIcon="@drawable/ic_search_hint" |
||||||
|
app:goIcon="@drawable/ic_search" |
||||||
app:defaultQueryHint="搜索"/> |
app:defaultQueryHint="搜索"/> |
Loading…
Reference in new issue