├── README.md
├── app
├── .gitignore
├── src
│ └── main
│ │ ├── assets
│ │ ├── libstyTool.so
│ │ ├── animation.dex
│ │ └── data.mp3
│ │ ├── java
│ │ └── nico
│ │ │ └── styTool
│ │ │ └── plus
│ │ │ ├── BinStr.java
│ │ │ ├── On.java
│ │ │ ├── App.java
│ │ │ ├── CardViewDelegate.java
│ │ │ ├── CardViewJellybeanMr1.java
│ │ │ ├── DBSearchHelper.java
│ │ │ ├── SearchHistorysBean.java
│ │ │ ├── GankIoActivity.java
│ │ │ ├── CardViewImpl.java
│ │ │ ├── BlurBitmapUtil.java
│ │ │ ├── DarkFrameLayout.java
│ │ │ ├── Bookmark.java
│ │ │ ├── ListShower.java
│ │ │ ├── Constant.java
│ │ │ ├── SearchHistorysDao.java
│ │ │ ├── CardViewApi21.java
│ │ │ ├── RoundRectDrawable.java
│ │ │ ├── CardViewEclairMr1.java
│ │ │ ├── RoundRectDrawableWithShadow.java
│ │ │ ├── CardView.java
│ │ │ ├── Num.java
│ │ │ ├── MaterialDialog.java
│ │ │ └── SlideBottomPanel.java
│ │ ├── res
│ │ ├── drawable-hdpi
│ │ │ ├── image.png
│ │ │ ├── wifi_file.png
│ │ │ ├── ic_launcher.png
│ │ │ ├── notification.png
│ │ │ ├── wifi_automatic.png
│ │ │ ├── ic_adb_white_24dp.png
│ │ │ ├── ic_edit_white_24dp.png
│ │ │ ├── ic_send_white_24dp.png
│ │ │ ├── ic_stop_white_24dp.png
│ │ │ ├── ic_pause_white_24dp.png
│ │ │ ├── ic_photo_white_24dp.png
│ │ │ ├── ic_add_alert_white_24dp.png
│ │ │ ├── ic_arrow_back_white_24dp.png
│ │ │ ├── ic_play_arrow_white_24dp.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_000.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_015.png
│ │ │ └── ic_insert_emoticon_white_24dp.png
│ │ ├── drawable-xxhdpi
│ │ │ ├── ser.png
│ │ │ ├── sr.png
│ │ │ ├── fals.png
│ │ │ ├── iml_s.png
│ │ │ ├── abc_vei.png
│ │ │ ├── box_notes.png
│ │ │ ├── ic_http_48px.png
│ │ │ ├── ic_https_48px.png
│ │ │ ├── ic_menu_black_24dp.png
│ │ │ ├── ic_refresh_black_24dp.png
│ │ │ ├── ic_chevron_left_black_24dp.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_000.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_015.png
│ │ │ └── ic_chevron_right_black_24dp.png
│ │ ├── drawable-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_adb_white_24dp.png
│ │ │ ├── ic_edit_white_24dp.png
│ │ │ ├── ic_send_white_24dp.png
│ │ │ ├── ic_stop_white_24dp.png
│ │ │ ├── ic_pause_white_24dp.png
│ │ │ ├── ic_photo_white_24dp.png
│ │ │ ├── ic_add_alert_white_24dp.png
│ │ │ ├── ic_arrow_back_white_24dp.png
│ │ │ ├── ic_play_arrow_white_24dp.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_000.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_015.png
│ │ │ └── ic_insert_emoticon_white_24dp.png
│ │ ├── drawable-nodpi
│ │ │ ├── emoji_0030.png
│ │ │ ├── emoji_0031.png
│ │ │ ├── emoji_0032.png
│ │ │ ├── emoji_0033.png
│ │ │ ├── emoji_0034.png
│ │ │ ├── emoji_0035.png
│ │ │ ├── emoji_0036.png
│ │ │ ├── emoji_0037.png
│ │ │ ├── emoji_0038.png
│ │ │ ├── emoji_0039.png
│ │ │ └── emoji_26a1.png
│ │ ├── drawable-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_adb_white_24dp.png
│ │ │ ├── ic_edit_white_24dp.png
│ │ │ ├── ic_pause_white_24dp.png
│ │ │ ├── ic_photo_white_24dp.png
│ │ │ ├── ic_send_white_24dp.png
│ │ │ ├── ic_stop_white_24dp.png
│ │ │ ├── ic_add_alert_white_24dp.png
│ │ │ ├── ic_arrow_back_white_24dp.png
│ │ │ ├── ic_play_arrow_white_24dp.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_000.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_015.png
│ │ │ └── ic_insert_emoticon_white_24dp.png
│ │ ├── drawable
│ │ │ ├── bga_sbl_shadow.9.png
│ │ │ ├── bg_button_normal.xml
│ │ │ ├── bg_button_pressed.xml
│ │ │ ├── material_dialog_window.xml
│ │ │ ├── cs_b.xml
│ │ │ ├── button.xml
│ │ │ └── material_card.xml
│ │ ├── drawable-xxxhdpi
│ │ │ ├── ic_adb_white_24dp.png
│ │ │ ├── ic_edit_white_24dp.png
│ │ │ ├── ic_pause_white_24dp.png
│ │ │ ├── ic_photo_white_24dp.png
│ │ │ ├── ic_send_white_24dp.png
│ │ │ ├── ic_stop_white_24dp.png
│ │ │ ├── ic_add_alert_white_24dp.png
│ │ │ ├── ic_arrow_back_white_24dp.png
│ │ │ ├── ic_play_arrow_white_24dp.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_000.png
│ │ │ ├── abc_btn_radio_to_on_mtrl_015.png
│ │ │ └── ic_insert_emoticon_white_24dp.png
│ │ ├── values
│ │ │ ├── bga_sbl_integers.xml
│ │ │ ├── strings.xml
│ │ │ ├── dimens.xml
│ │ │ ├── attrs_circle_progressbar.xml
│ │ │ ├── colors.xml
│ │ │ ├── styles.xml
│ │ │ └── attrs.xml
│ │ ├── anim
│ │ │ ├── window_back.xml
│ │ │ ├── window_out.xml
│ │ │ ├── bga_sbl_activity_swipeback_enter.xml
│ │ │ ├── bga_sbl_activity_swipeback_exit.xml
│ │ │ ├── bga_sbl_activity_backward_exit.xml
│ │ │ ├── bga_sbl_activity_forward_enter.xml
│ │ │ ├── bga_sbl_activity_forward_exit.xml
│ │ │ └── bga_sbl_activity_backward_enter.xml
│ │ ├── layout
│ │ │ ├── ut.xml
│ │ │ ├── history.xml
│ │ │ ├── item_search_history_word.xml
│ │ │ ├── historylist.xml
│ │ │ ├── main.xml
│ │ │ ├── window_popup.xml
│ │ │ ├── th.xml
│ │ │ ├── layout_material_dialog.xml
│ │ │ └── a_host.xml
│ │ ├── menu
│ │ │ └── headmenu.xml
│ │ └── xml
│ │ │ └── ganklo.xml
│ │ └── AndroidManifest.xml
├── libs
│ ├── library-2.4.0.jar
│ └── zxing-core-3.1.0.jar
└── build.gradle
├── settings.gradle
├── .idea
├── dictionaries
│ └── sty.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── gradlew
└── LICENSE
/README.md:
--------------------------------------------------------------------------------
1 | QQ 2284467793
2 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/src/main/assets/libstyTool.so:
--------------------------------------------------------------------------------
1 | ?elf
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/assets/animation.dex:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/assets/data.mp3:
--------------------------------------------------------------------------------
1 | ���� #�-�� t2%�7�}X>���"��1Y�a�^X*��k06���h�
--------------------------------------------------------------------------------
/app/libs/library-2.4.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stytooldex/pius1/HEAD/app/libs/library-2.4.0.jar
--------------------------------------------------------------------------------
/app/libs/zxing-core-3.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stytooldex/pius1/HEAD/app/libs/zxing-core-3.1.0.jar
--------------------------------------------------------------------------------
/.idea/dictionaries/sty.xml:
--------------------------------------------------------------------------------
1 |
9 | * Necessary to resolve circular dependency between base CardView and platform implementations.
10 | */
11 | interface CardViewDelegate {
12 | void setBackgroundDrawable(Drawable paramDrawable);
13 | Drawable getBackground();
14 | boolean getUseCompatPadding();
15 | boolean getPreventCornerOverlap();
16 | float getRadius();
17 | void setShadowPadding(int left, int top, int right, int bottom);
18 | }
19 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 | * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable.
21 | */
22 | class RoundRectDrawable extends Drawable {
23 | private float mRadius;
24 | private final Paint mPaint;
25 | private final RectF mBoundsF;
26 | private final Rect mBoundsI;
27 | private float mPadding;
28 | private boolean mInsetForPadding = false;
29 | private boolean mInsetForRadius = true;
30 |
31 | public RoundRectDrawable(int backgroundColor, float radius) {
32 | mRadius = radius;
33 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
34 | mPaint.setColor(backgroundColor);
35 | mBoundsF = new RectF();
36 | mBoundsI = new Rect();
37 | }
38 |
39 | void setPadding(float padding, boolean insetForPadding, boolean insetForRadius) {
40 | if (padding == mPadding && mInsetForPadding == insetForPadding &&
41 | mInsetForRadius == insetForRadius) {
42 | return;
43 | }
44 | mPadding = padding;
45 | mInsetForPadding = insetForPadding;
46 | mInsetForRadius = insetForRadius;
47 | updateBounds(null);
48 | invalidateSelf();
49 | }
50 |
51 | float getPadding() {
52 | return mPadding;
53 | }
54 |
55 | @Override
56 | public void draw(Canvas canvas) {
57 | canvas.drawRoundRect(mBoundsF, mRadius, mRadius, mPaint);
58 | }
59 |
60 | private void updateBounds(Rect bounds) {
61 | if (bounds == null) {
62 | bounds = getBounds();
63 | }
64 | mBoundsF.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
65 | mBoundsI.set(bounds);
66 | if (mInsetForPadding) {
67 | float vInset = calculateVerticalPadding(mPadding, mRadius, mInsetForRadius);
68 | float hInset = calculateHorizontalPadding(mPadding, mRadius, mInsetForRadius);
69 | mBoundsI.inset((int) Math.ceil(hInset), (int) Math.ceil(vInset));
70 | // to make sure they have same bounds.
71 | mBoundsF.set(mBoundsI);
72 | }
73 | }
74 |
75 | @Override
76 | protected void onBoundsChange(Rect bounds) {
77 | super.onBoundsChange(bounds);
78 | updateBounds(bounds);
79 | }
80 |
81 | @Override
82 | public void getOutline(Outline outline) {
83 | outline.setRoundRect(mBoundsI, mRadius);
84 | }
85 |
86 | void setRadius(float radius) {
87 | if (radius == mRadius) {
88 | return;
89 | }
90 | mRadius = radius;
91 | updateBounds(null);
92 | invalidateSelf();
93 | }
94 |
95 | @Override
96 | public void setAlpha(int alpha) {
97 | // not supported because older versions do not support
98 | }
99 |
100 | @Override
101 | public void setColorFilter(ColorFilter cf) {
102 | // not supported because older versions do not support
103 | }
104 |
105 | @Override
106 | public int getOpacity() {
107 | return PixelFormat.TRANSLUCENT;
108 | }
109 |
110 | public float getRadius() {
111 | return mRadius;
112 | }
113 |
114 | public void setColor(int color) {
115 | mPaint.setColor(color);
116 | invalidateSelf();
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
17 |
22 |
27 |
99 |
101 |
31 | * Prior to API 17, canvas.drawRoundRect is expensive; which is why we need this interface 32 | * to draw efficient rounded rectangles before 17. 33 | * */ 34 | static RoundRectHelper sRoundRectHelper; 35 | 36 | Paint mPaint; 37 | 38 | Paint mCornerShadowPaint; 39 | 40 | Paint mEdgeShadowPaint; 41 | 42 | final RectF mCardBounds; 43 | 44 | float mCornerRadius; 45 | 46 | Path mCornerShadowPath; 47 | 48 | // updated value with inset 49 | float mMaxShadowSize; 50 | 51 | // actual value set by developer 52 | float mRawMaxShadowSize; 53 | 54 | // multiplied value to account for shadow offset 55 | float mShadowSize; 56 | 57 | // actual value set by developer 58 | float mRawShadowSize; 59 | 60 | private boolean mDirty = true; 61 | 62 | private final int mShadowStartColor; 63 | 64 | private final int mShadowEndColor; 65 | 66 | private boolean mAddPaddingForCorners = true; 67 | 68 | /** 69 | * If shadow size is set to a value above max shadow, we print a warning 70 | */ 71 | private boolean mPrintedShadowClipWarning = false; 72 | 73 | RoundRectDrawableWithShadow(Resources resources, int backgroundColor, float radius, 74 | float shadowSize, float maxShadowSize) { 75 | mShadowStartColor = resources.getColor(R.color.cardview_shadow_start_color); 76 | mShadowEndColor = resources.getColor(R.color.cardview_shadow_end_color); 77 | mInsetShadow = resources.getDimensionPixelSize(R.dimen.cardview_compat_inset_shadow); 78 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); 79 | mPaint.setColor(backgroundColor); 80 | mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); 81 | mCornerShadowPaint.setStyle(Paint.Style.FILL); 82 | mCornerRadius = (int) (radius + .5f); 83 | mCardBounds = new RectF(); 84 | mEdgeShadowPaint = new Paint(mCornerShadowPaint); 85 | mEdgeShadowPaint.setAntiAlias(false); 86 | setShadowSize(shadowSize, maxShadowSize); 87 | } 88 | 89 | /** 90 | * Casts the value to an even integer. 91 | */ 92 | private int toEven(float value) { 93 | int i = (int) (value + .5f); 94 | if (i % 2 == 1) { 95 | return i - 1; 96 | } 97 | return i; 98 | } 99 | 100 | public void setAddPaddingForCorners(boolean addPaddingForCorners) { 101 | mAddPaddingForCorners = addPaddingForCorners; 102 | invalidateSelf(); 103 | } 104 | 105 | @Override 106 | public void setAlpha(int alpha) { 107 | mPaint.setAlpha(alpha); 108 | mCornerShadowPaint.setAlpha(alpha); 109 | mEdgeShadowPaint.setAlpha(alpha); 110 | } 111 | 112 | @Override 113 | protected void onBoundsChange(Rect bounds) { 114 | super.onBoundsChange(bounds); 115 | mDirty = true; 116 | } 117 | 118 | void setShadowSize(float shadowSize, float maxShadowSize) { 119 | if (shadowSize < 0 || maxShadowSize < 0) { 120 | throw new IllegalArgumentException("invalid shadow size"); 121 | } 122 | shadowSize = toEven(shadowSize); 123 | maxShadowSize = toEven(maxShadowSize); 124 | if (shadowSize > maxShadowSize) { 125 | shadowSize = maxShadowSize; 126 | if (!mPrintedShadowClipWarning) { 127 | mPrintedShadowClipWarning = true; 128 | } 129 | } 130 | if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) { 131 | return; 132 | } 133 | mRawShadowSize = shadowSize; 134 | mRawMaxShadowSize = maxShadowSize; 135 | mShadowSize = (int)(shadowSize * SHADOW_MULTIPLIER + mInsetShadow + .5f); 136 | mMaxShadowSize = maxShadowSize + mInsetShadow; 137 | mDirty = true; 138 | invalidateSelf(); 139 | } 140 | 141 | @Override 142 | public boolean getPadding(Rect padding) { 143 | int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius, 144 | mAddPaddingForCorners)); 145 | int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius, 146 | mAddPaddingForCorners)); 147 | padding.set(hOffset, vOffset, hOffset, vOffset); 148 | return true; 149 | } 150 | 151 | static float calculateVerticalPadding(float maxShadowSize, float cornerRadius, 152 | boolean addPaddingForCorners) { 153 | if (addPaddingForCorners) { 154 | return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius); 155 | } else { 156 | return maxShadowSize * SHADOW_MULTIPLIER; 157 | } 158 | } 159 | 160 | static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius, 161 | boolean addPaddingForCorners) { 162 | if (addPaddingForCorners) { 163 | return (float) (maxShadowSize + (1 - COS_45) * cornerRadius); 164 | } else { 165 | return maxShadowSize; 166 | } 167 | } 168 | 169 | @Override 170 | public void setColorFilter(ColorFilter cf) { 171 | mPaint.setColorFilter(cf); 172 | mCornerShadowPaint.setColorFilter(cf); 173 | mEdgeShadowPaint.setColorFilter(cf); 174 | } 175 | 176 | @Override 177 | public int getOpacity() { 178 | return PixelFormat.TRANSLUCENT; 179 | } 180 | 181 | void setCornerRadius(float radius) { 182 | radius = (int) (radius + .5f); 183 | if (mCornerRadius == radius) { 184 | return; 185 | } 186 | mCornerRadius = radius; 187 | mDirty = true; 188 | invalidateSelf(); 189 | } 190 | 191 | @Override 192 | public void draw(Canvas canvas) { 193 | if (mDirty) { 194 | buildComponents(getBounds()); 195 | mDirty = false; 196 | } 197 | canvas.translate(0, mRawShadowSize / 2); 198 | drawShadow(canvas); 199 | canvas.translate(0, -mRawShadowSize / 2); 200 | sRoundRectHelper.drawRoundRect(canvas, mCardBounds, mCornerRadius, mPaint); 201 | } 202 | 203 | private void drawShadow(Canvas canvas) { 204 | final float edgeShadowTop = -mCornerRadius - mShadowSize; 205 | final float inset = mCornerRadius + mInsetShadow + mRawShadowSize / 2; 206 | final boolean drawHorizontalEdges = mCardBounds.width() - 2 * inset > 0; 207 | final boolean drawVerticalEdges = mCardBounds.height() - 2 * inset > 0; 208 | // LT 209 | int saved = canvas.save(); 210 | canvas.translate(mCardBounds.left + inset, mCardBounds.top + inset); 211 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 212 | if (drawHorizontalEdges) { 213 | canvas.drawRect(0, edgeShadowTop, 214 | mCardBounds.width() - 2 * inset, -mCornerRadius, 215 | mEdgeShadowPaint); 216 | } 217 | canvas.restoreToCount(saved); 218 | // RB 219 | saved = canvas.save(); 220 | canvas.translate(mCardBounds.right - inset, mCardBounds.bottom - inset); 221 | canvas.rotate(180f); 222 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 223 | if (drawHorizontalEdges) { 224 | canvas.drawRect(0, edgeShadowTop, 225 | mCardBounds.width() - 2 * inset, -mCornerRadius + mShadowSize, 226 | mEdgeShadowPaint); 227 | } 228 | canvas.restoreToCount(saved); 229 | // LB 230 | saved = canvas.save(); 231 | canvas.translate(mCardBounds.left + inset, mCardBounds.bottom - inset); 232 | canvas.rotate(270f); 233 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 234 | if (drawVerticalEdges) { 235 | canvas.drawRect(0, edgeShadowTop, 236 | mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); 237 | } 238 | canvas.restoreToCount(saved); 239 | // RT 240 | saved = canvas.save(); 241 | canvas.translate(mCardBounds.right - inset, mCardBounds.top + inset); 242 | canvas.rotate(90f); 243 | canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 244 | if (drawVerticalEdges) { 245 | canvas.drawRect(0, edgeShadowTop, 246 | mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); 247 | } 248 | canvas.restoreToCount(saved); 249 | } 250 | 251 | private void buildShadowCorners() { 252 | RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius); 253 | RectF outerBounds = new RectF(innerBounds); 254 | outerBounds.inset(-mShadowSize, -mShadowSize); 255 | 256 | if (mCornerShadowPath == null) { 257 | mCornerShadowPath = new Path(); 258 | } else { 259 | mCornerShadowPath.reset(); 260 | } 261 | mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD); 262 | mCornerShadowPath.moveTo(-mCornerRadius, 0); 263 | mCornerShadowPath.rLineTo(-mShadowSize, 0); 264 | // outer arc 265 | mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false); 266 | // inner arc 267 | mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false); 268 | mCornerShadowPath.close(); 269 | float startRatio = mCornerRadius / (mCornerRadius + mShadowSize); 270 | mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize, 271 | new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, 272 | new float[]{0f, startRatio, 1f} 273 | , Shader.TileMode.CLAMP)); 274 | 275 | // we offset the content shadowSize/2 pixels up to make it more realistic. 276 | // this is why edge shadow shader has some extra space 277 | // When drawing bottom edge shadow, we use that extra space. 278 | mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0, 279 | -mCornerRadius - mShadowSize, 280 | new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, 281 | new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP)); 282 | mEdgeShadowPaint.setAntiAlias(false); 283 | } 284 | 285 | private void buildComponents(Rect bounds) { 286 | // Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift. 287 | // We could have different top-bottom offsets to avoid extra gap above but in that case 288 | // center aligning Views inside the CardView would be problematic. 289 | final float verticalOffset = mRawMaxShadowSize * SHADOW_MULTIPLIER; 290 | mCardBounds.set(bounds.left + mRawMaxShadowSize, bounds.top + verticalOffset, 291 | bounds.right - mRawMaxShadowSize, bounds.bottom - verticalOffset); 292 | buildShadowCorners(); 293 | } 294 | 295 | float getCornerRadius() { 296 | return mCornerRadius; 297 | } 298 | 299 | void getMaxShadowAndCornerPadding(Rect into) { 300 | getPadding(into); 301 | } 302 | 303 | void setShadowSize(float size) { 304 | setShadowSize(size, mRawMaxShadowSize); 305 | } 306 | 307 | void setMaxShadowSize(float size) { 308 | setShadowSize(mRawShadowSize, size); 309 | } 310 | 311 | float getShadowSize() { 312 | return mRawShadowSize; 313 | } 314 | 315 | float getMaxShadowSize() { 316 | return mRawMaxShadowSize; 317 | } 318 | 319 | float getMinWidth() { 320 | final float content = 2 * 321 | Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize / 2); 322 | return content + (mRawMaxShadowSize + mInsetShadow) * 2; 323 | } 324 | 325 | float getMinHeight() { 326 | final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow 327 | + mRawMaxShadowSize * SHADOW_MULTIPLIER / 2); 328 | return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER + mInsetShadow) * 2; 329 | } 330 | 331 | public void setColor(int color) { 332 | mPaint.setColor(color); 333 | invalidateSelf(); 334 | } 335 | 336 | static interface RoundRectHelper { 337 | void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint); 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /app/src/main/java/nico/styTool/plus/CardView.java: -------------------------------------------------------------------------------- 1 | package nico.styTool.plus; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Rect; 6 | import android.os.Build; 7 | import android.util.AttributeSet; 8 | import android.widget.FrameLayout; 9 | 10 | /** 11 | * A FrameLayout with a rounded corner background and shadow. 12 | *
13 | * CardView uses elevation property on L for shadows and falls back to a custom shadow
14 | * implementation on older platforms.
15 | *
16 | * Due to expensive nature of rounded corner clipping, on platforms before L, CardView does not 17 | * clip its children that intersect with rounded corners. Instead, it adds padding to avoid such 18 | * intersection (See {@link #setPreventCornerOverlap(boolean)} to change this behavior). 19 | *
20 | * Before L, CardView adds padding to its content and draws shadows to that area. This padding
21 | * amount is equal to maxCardElevation + (1 - cos45) * cornerRadius on the sides and
22 | * maxCardElevation * 1.5 + (1 - cos45) * cornerRadius on top and bottom.
23 | *
24 | * Since padding is used to offset content for shadows, you cannot set padding on CardView. 25 | * Instead, 26 | * you can use content padding attributes in XML or {@link #setContentPadding(int, int, int, int)} 27 | * in code to set the padding between the edges of the Card and children of CardView. 28 | *
29 | * Note that, if you specify exact dimensions for the CardView, because of the shadows, its content
30 | * area will be different between platforms before L and after L. By using api version specific
31 | * resource values, you can avoid these changes. Alternatively, If you want CardView to add inner
32 | * padding on platforms L and after as well, you can set {@link #setUseCompatPadding(boolean)} to
33 | * true.
34 | *
35 | * To change CardView's elevation in a backward compatible way, use 36 | * {@link #setCardElevation(float)}. CardView will use elevation API on L and before L, it will 37 | * change the shadow size. To avoid moving the View while shadow size is changing, shadow size is 38 | * clamped by {@link #getMaxCardElevation()}. If you want to change elevation dynamically, you 39 | * should call {@link #setMaxCardElevation(float)} when CardView is initialized. 40 | * 41 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor 42 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardCornerRadius 43 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation 44 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardMaxElevation 45 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardUseCompatPadding 46 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardPreventCornerOverlap 47 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPadding 48 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingLeft 49 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingTop 50 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingRight 51 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingBottom 52 | */ 53 | public class CardView extends FrameLayout implements CardViewDelegate { 54 | 55 | private static final CardViewImpl IMPL; 56 | 57 | static { 58 | if (Build.VERSION.SDK_INT >= 21) { 59 | IMPL = new CardViewApi21(); 60 | } else if (Build.VERSION.SDK_INT >= 17) { 61 | IMPL = new CardViewJellybeanMr1(); 62 | } else { 63 | IMPL = new CardViewEclairMr1(); 64 | } 65 | IMPL.initStatic(); 66 | } 67 | 68 | private boolean mCompatPadding; 69 | 70 | private boolean mPreventCornerOverlap; 71 | 72 | private final Rect mContentPadding = new Rect(); 73 | 74 | private final Rect mShadowBounds = new Rect(); 75 | 76 | 77 | public CardView(Context context) { 78 | super(context); 79 | initialize(context, null, 0); 80 | } 81 | 82 | public CardView(Context context, AttributeSet attrs) { 83 | super(context, attrs); 84 | initialize(context, attrs, 0); 85 | } 86 | 87 | public CardView(Context context, AttributeSet attrs, int defStyleAttr) { 88 | super(context, attrs, defStyleAttr); 89 | initialize(context, attrs, defStyleAttr); 90 | } 91 | 92 | @Override 93 | public void setPadding(int left, int top, int right, int bottom) { 94 | // NO OP 95 | } 96 | 97 | public void setPaddingRelative(int start, int top, int end, int bottom) { 98 | // NO OP 99 | } 100 | 101 | /** 102 | * Returns whether CardView will add inner padding on platforms L and after. 103 | * 104 | * @return True CardView adds inner padding on platforms L and after to have same dimensions 105 | * with platforms before L. 106 | */ 107 | @Override 108 | public boolean getUseCompatPadding() { 109 | return mCompatPadding; 110 | } 111 | 112 | /** 113 | * CardView adds additional padding to draw shadows on platforms before L. 114 | *
115 | * This may cause Cards to have different sizes between L and before L. If you need to align
116 | * CardView with other Views, you may need api version specific dimension resources to account
117 | * for the changes.
118 | * As an alternative, you can set this flag to true and CardView will add the same
119 | * padding values on platforms L and after.
120 | *
121 | * Since setting this flag to true adds unnecessary gaps in the UI, default value is
122 | * false.
123 | *
124 | * @param useCompatPadding True if CardView should add padding for the shadows on platforms L
125 | * and above.
126 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardUseCompatPadding
127 | */
128 | public void setUseCompatPadding(boolean useCompatPadding) {
129 | if (mCompatPadding == useCompatPadding) {
130 | return;
131 | }
132 | mCompatPadding = useCompatPadding;
133 | IMPL.onCompatPaddingChanged(this);
134 | }
135 |
136 | /**
137 | * Sets the padding between the Card's edges and the children of CardView.
138 | *
139 | * Depending on platform version or {@link #getUseCompatPadding()} settings, CardView may 140 | * update these values before calling {@link android.view.View#setPadding(int, int, int, int)}. 141 | * 142 | * @param left The left padding in pixels 143 | * @param top The top padding in pixels 144 | * @param right The right padding in pixels 145 | * @param bottom The bottom padding in pixels 146 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPadding 147 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingLeft 148 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingTop 149 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingRight 150 | * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingBottom 151 | */ 152 | public void setContentPadding(int left, int top, int right, int bottom) { 153 | mContentPadding.set(left, top, right, bottom); 154 | IMPL.updatePadding(this); 155 | } 156 | 157 | @Override 158 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 159 | if (IMPL instanceof CardViewApi21 == false) { 160 | final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 161 | switch (widthMode) { 162 | case MeasureSpec.EXACTLY: 163 | case MeasureSpec.AT_MOST: 164 | final int minWidth = (int) Math.ceil(IMPL.getMinWidth(this)); 165 | widthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minWidth, 166 | MeasureSpec.getSize(widthMeasureSpec)), widthMode); 167 | break; 168 | } 169 | 170 | final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 171 | switch (heightMode) { 172 | case MeasureSpec.EXACTLY: 173 | case MeasureSpec.AT_MOST: 174 | final int minHeight = (int) Math.ceil(IMPL.getMinHeight(this)); 175 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minHeight, 176 | MeasureSpec.getSize(heightMeasureSpec)), heightMode); 177 | break; 178 | } 179 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 180 | } else { 181 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 182 | } 183 | } 184 | 185 | private void initialize(Context context, AttributeSet attrs, int defStyleAttr) { 186 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CardView, defStyleAttr, 187 | R.style.CardView_Light); 188 | int backgroundColor = a.getColor(R.styleable.CardView_cardBackgroundColor, 0); 189 | float radius = a.getDimension(R.styleable.CardView_cardCornerRadius, 0); 190 | float elevation = a.getDimension(R.styleable.CardView_cardElevation, 0); 191 | float maxElevation = a.getDimension(R.styleable.CardView_cardMaxElevation, 0); 192 | mCompatPadding = a.getBoolean(R.styleable.CardView_cardUseCompatPadding, false); 193 | mPreventCornerOverlap = a.getBoolean(R.styleable.CardView_cardPreventCornerOverlap, true); 194 | int defaultPadding = a.getDimensionPixelSize(R.styleable.CardView_contentPadding, 0); 195 | mContentPadding.left = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingLeft, 196 | defaultPadding); 197 | mContentPadding.top = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingTop, 198 | defaultPadding); 199 | mContentPadding.right = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingRight, 200 | defaultPadding); 201 | mContentPadding.bottom = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingBottom, 202 | defaultPadding); 203 | if (elevation > maxElevation) { 204 | maxElevation = elevation; 205 | } 206 | a.recycle(); 207 | IMPL.initialize(this, context, backgroundColor, radius, elevation, maxElevation); 208 | } 209 | 210 | /** 211 | * Updates the background color of the CardView 212 | * 213 | * @param color The new color to set for the card background 214 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor 215 | */ 216 | public void setCardBackgroundColor(int color) { 217 | IMPL.setBackgroundColor(this, color); 218 | } 219 | 220 | /** 221 | * Returns the inner padding after the Card's left edge 222 | * 223 | * @return the inner padding after the Card's left edge 224 | */ 225 | public int getContentPaddingLeft() { 226 | return mContentPadding.left; 227 | } 228 | 229 | /** 230 | * Returns the inner padding before the Card's right edge 231 | * 232 | * @return the inner padding before the Card's right edge 233 | */ 234 | public int getContentPaddingRight() { 235 | return mContentPadding.right; 236 | } 237 | 238 | /** 239 | * Returns the inner padding after the Card's top edge 240 | * 241 | * @return the inner padding after the Card's top edge 242 | */ 243 | public int getContentPaddingTop() { 244 | return mContentPadding.top; 245 | } 246 | 247 | /** 248 | * Returns the inner padding before the Card's bottom edge 249 | * 250 | * @return the inner padding before the Card's bottom edge 251 | */ 252 | public int getContentPaddingBottom() { 253 | return mContentPadding.bottom; 254 | } 255 | 256 | /** 257 | * Updates the corner radius of the CardView. 258 | * 259 | * @param radius The radius in pixels of the corners of the rectangle shape 260 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardCornerRadius 261 | * @see #setRadius(float) 262 | */ 263 | public void setRadius(float radius) { 264 | IMPL.setRadius(this, radius); 265 | } 266 | 267 | /** 268 | * Returns the corner radius of the CardView. 269 | * 270 | * @return Corner radius of the CardView 271 | * @see #getRadius() 272 | */ 273 | public float getRadius() { 274 | return IMPL.getRadius(this); 275 | } 276 | 277 | /** 278 | * Internal method used by CardView implementations to update the padding. 279 | * 280 | * @hide 281 | */ 282 | @Override 283 | public void setShadowPadding(int left, int top, int right, int bottom) { 284 | mShadowBounds.set(left, top, right, bottom); 285 | super.setPadding(left + mContentPadding.left, top + mContentPadding.top, 286 | right + mContentPadding.right, bottom + mContentPadding.bottom); 287 | } 288 | 289 | /** 290 | * Updates the backward compatible elevation of the CardView. 291 | * 292 | * @param radius The backward compatible elevation in pixels. 293 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation 294 | * @see #getCardElevation() 295 | * @see #setMaxCardElevation(float) 296 | */ 297 | public void setCardElevation(float radius) { 298 | IMPL.setElevation(this, radius); 299 | } 300 | 301 | /** 302 | * Returns the backward compatible elevation of the CardView. 303 | * 304 | * @return Elevation of the CardView 305 | * @see #setCardElevation(float) 306 | * @see #getMaxCardElevation() 307 | */ 308 | public float getCardElevation() { 309 | return IMPL.getElevation(this); 310 | } 311 | 312 | /** 313 | * Updates the backward compatible elevation of the CardView. 314 | *
315 | * Calling this method has no effect if device OS version is L or newer and
316 | * {@link #getUseCompatPadding()} is false.
317 | *
318 | * @param radius The backward compatible elevation in pixels.
319 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation
320 | * @see #setCardElevation(float)
321 | * @see #getMaxCardElevation()
322 | */
323 | public void setMaxCardElevation(float radius) {
324 | IMPL.setMaxElevation(this, radius);
325 | }
326 |
327 | /**
328 | * Returns the backward compatible elevation of the CardView.
329 | *
330 | * @return Elevation of the CardView
331 | * @see #setMaxCardElevation(float)
332 | * @see #getCardElevation()
333 | */
334 | public float getMaxCardElevation() {
335 | return IMPL.getMaxElevation(this);
336 | }
337 |
338 | /**
339 | * Returns whether CardView should add extra padding to content to avoid overlaps with rounded
340 | * corners on API versions 20 and below.
341 | *
342 | * @return True if CardView prevents overlaps with rounded corners on platforms before L.
343 | * Default value is true.
344 | */
345 | @Override
346 | public boolean getPreventCornerOverlap() {
347 | return mPreventCornerOverlap;
348 | }
349 |
350 | /**
351 | * On API 20 and before, CardView does not clip the bounds of the Card for the rounded corners.
352 | * Instead, it adds padding to content so that it won't overlap with the rounded corners.
353 | * You can disable this behavior by setting this field to false.
354 | *
355 | * Setting this value on API 21 and above does not have any effect unless you have enabled 356 | * compatibility padding. 357 | * 358 | * @param preventCornerOverlap Whether CardView should add extra padding to content to avoid 359 | * overlaps with the CardView corners. 360 | * @attr ref android.support.v7.cardview.R.styleable#CardView_cardPreventCornerOverlap 361 | * @see #setUseCompatPadding(boolean) 362 | */ 363 | public void setPreventCornerOverlap(boolean preventCornerOverlap) { 364 | if (preventCornerOverlap == mPreventCornerOverlap) { 365 | return; 366 | } 367 | mPreventCornerOverlap = preventCornerOverlap; 368 | IMPL.onPreventCornerOverlapChanged(this); 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /app/src/main/java/nico/styTool/plus/Num.java: -------------------------------------------------------------------------------- 1 | package nico.styTool.plus; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.RectF; 9 | import android.os.Bundle; 10 | import android.os.Parcelable; 11 | import android.util.AttributeSet; 12 | import android.view.View; 13 | 14 | import static nico.styTool.plus.Num.ProgressTextVisibility.Invisible; 15 | import static nico.styTool.plus.Num.ProgressTextVisibility.Visible; 16 | 17 | /** 18 | * Created by daimajia on 14-4-30. 19 | */ 20 | public class Num extends View { 21 | private int mMaxProgress = 100; 22 | 23 | /** 24 | * Current progress, can not exceed the max progress. 25 | */ 26 | private int mCurrentProgress = 0; 27 | 28 | /** 29 | * The progress area bar color. 30 | */ 31 | private int mReachedBarColor; 32 | 33 | /** 34 | * The bar unreached area color. 35 | */ 36 | private int mUnreachedBarColor; 37 | 38 | /** 39 | * The progress text color. 40 | */ 41 | private int mTextColor; 42 | 43 | /** 44 | * The progress text size. 45 | */ 46 | private float mTextSize; 47 | 48 | /** 49 | * The height of the reached area. 50 | */ 51 | private float mReachedBarHeight; 52 | 53 | /** 54 | * The height of the unreached area. 55 | */ 56 | private float mUnreachedBarHeight; 57 | 58 | /** 59 | * The suffix of the number. 60 | */ 61 | private String mSuffix = "%"; 62 | 63 | /** 64 | * The prefix. 65 | */ 66 | private String mPrefix = ""; 67 | 68 | 69 | private final int default_text_color = Color.rgb(66, 145, 241); 70 | private final int default_reached_color = Color.rgb(66, 145, 241); 71 | private final int default_unreached_color = Color.rgb(204, 204, 204); 72 | private final float default_progress_text_offset; 73 | private final float default_text_size; 74 | private final float default_reached_bar_height; 75 | private final float default_unreached_bar_height; 76 | 77 | /** 78 | * For save and restore instance of progressbar. 79 | */ 80 | private static final String INSTANCE_STATE = "saved_instance"; 81 | private static final String INSTANCE_TEXT_COLOR = "text_color"; 82 | private static final String INSTANCE_TEXT_SIZE = "text_size"; 83 | private static final String INSTANCE_REACHED_BAR_HEIGHT = "reached_bar_height"; 84 | private static final String INSTANCE_REACHED_BAR_COLOR = "reached_bar_color"; 85 | private static final String INSTANCE_UNREACHED_BAR_HEIGHT = "unreached_bar_height"; 86 | private static final String INSTANCE_UNREACHED_BAR_COLOR = "unreached_bar_color"; 87 | private static final String INSTANCE_MAX = "max"; 88 | private static final String INSTANCE_PROGRESS = "progress"; 89 | private static final String INSTANCE_SUFFIX = "suffix"; 90 | private static final String INSTANCE_PREFIX = "prefix"; 91 | private static final String INSTANCE_TEXT_VISIBILITY = "text_visibility"; 92 | 93 | private static final int PROGRESS_TEXT_VISIBLE = 0; 94 | 95 | 96 | /** 97 | * The width of the text that to be drawn. 98 | */ 99 | private float mDrawTextWidth; 100 | 101 | /** 102 | * The drawn text start. 103 | */ 104 | private float mDrawTextStart; 105 | 106 | /** 107 | * The drawn text end. 108 | */ 109 | private float mDrawTextEnd; 110 | 111 | /** 112 | * The text that to be drawn in onDraw(). 113 | */ 114 | private String mCurrentDrawText; 115 | 116 | /** 117 | * The Paint of the reached area. 118 | */ 119 | private Paint mReachedBarPaint; 120 | /** 121 | * The Paint of the unreached area. 122 | */ 123 | private Paint mUnreachedBarPaint; 124 | /** 125 | * The Paint of the progress text. 126 | */ 127 | private Paint mTextPaint; 128 | 129 | /** 130 | * Unreached bar area to draw rect. 131 | */ 132 | private RectF mUnreachedRectF = new RectF(0, 0, 0, 0); 133 | /** 134 | * Reached bar area rect. 135 | */ 136 | private RectF mReachedRectF = new RectF(0, 0, 0, 0); 137 | 138 | /** 139 | * The progress text offset. 140 | */ 141 | private float mOffset; 142 | 143 | /** 144 | * Determine if need to draw unreached area. 145 | */ 146 | private boolean mDrawUnreachedBar = true; 147 | 148 | private boolean mDrawReachedBar = true; 149 | 150 | private boolean mIfDrawText = true; 151 | 152 | /** 153 | * Listener 154 | */ 155 | private On mListener; 156 | 157 | public enum ProgressTextVisibility { 158 | Visible, Invisible 159 | } 160 | 161 | public Num(Context context) { 162 | this(context, null); 163 | } 164 | 165 | public Num(Context context, AttributeSet attrs) { 166 | this(context, attrs, R.attr.numberProgressBarStyle); 167 | } 168 | 169 | public Num(Context context, AttributeSet attrs, int defStyleAttr) { 170 | super(context, attrs, defStyleAttr); 171 | 172 | default_reached_bar_height = dp2px(1.5f); 173 | default_unreached_bar_height = dp2px(1.0f); 174 | default_text_size = sp2px(10); 175 | default_progress_text_offset = dp2px(3.0f); 176 | 177 | //load styled attributes. 178 | final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MaterialRefreshLayout, 179 | defStyleAttr, 0); 180 | 181 | mReachedBarColor = attributes.getColor(R.styleable.MaterialRefreshLayout_progress_reached_color, default_reached_color); 182 | mUnreachedBarColor = attributes.getColor(R.styleable.MaterialRefreshLayout_progress_unreached_color, default_unreached_color); 183 | mTextColor = attributes.getColor(R.styleable.MaterialRefreshLayout_progress_text_color, default_text_color); 184 | mTextSize = attributes.getDimension(R.styleable.MaterialRefreshLayout_progress_text_size, default_text_size); 185 | 186 | mReachedBarHeight = attributes.getDimension(R.styleable.MaterialRefreshLayout_progress_reached_bar_height, default_reached_bar_height); 187 | mUnreachedBarHeight = attributes.getDimension(R.styleable.MaterialRefreshLayout_progress_unreached_bar_height, default_unreached_bar_height); 188 | mOffset = attributes.getDimension(R.styleable.MaterialRefreshLayout_progress_text_offset, default_progress_text_offset); 189 | 190 | int textVisible = attributes.getInt(R.styleable.MaterialRefreshLayout_progress_text_visibility, PROGRESS_TEXT_VISIBLE); 191 | if (textVisible != PROGRESS_TEXT_VISIBLE) { 192 | mIfDrawText = false; 193 | } 194 | 195 | setProgress(attributes.getInt(R.styleable.MaterialRefreshLayout_progress_current, 0)); 196 | setMax(attributes.getInt(R.styleable.MaterialRefreshLayout_progress_max, 100)); 197 | 198 | attributes.recycle(); 199 | initializePainters(); 200 | } 201 | 202 | @Override 203 | protected int getSuggestedMinimumWidth() { 204 | return (int) mTextSize; 205 | } 206 | 207 | @Override 208 | protected int getSuggestedMinimumHeight() { 209 | return Math.max((int) mTextSize, Math.max((int) mReachedBarHeight, (int) mUnreachedBarHeight)); 210 | } 211 | 212 | @Override 213 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 214 | setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false)); 215 | } 216 | 217 | private int measure(int measureSpec, boolean isWidth) { 218 | int result; 219 | int mode = MeasureSpec.getMode(measureSpec); 220 | int size = MeasureSpec.getSize(measureSpec); 221 | int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom(); 222 | if (mode == MeasureSpec.EXACTLY) { 223 | result = size; 224 | } else { 225 | result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight(); 226 | result += padding; 227 | if (mode == MeasureSpec.AT_MOST) { 228 | if (isWidth) { 229 | result = Math.max(result, size); 230 | } else { 231 | result = Math.min(result, size); 232 | } 233 | } 234 | } 235 | return result; 236 | } 237 | 238 | @Override 239 | protected void onDraw(Canvas canvas) { 240 | if (mIfDrawText) { 241 | calculateDrawRectF(); 242 | } else { 243 | calculateDrawRectFWithoutProgressText(); 244 | } 245 | 246 | if (mDrawReachedBar) { 247 | canvas.drawRect(mReachedRectF, mReachedBarPaint); 248 | } 249 | 250 | if (mDrawUnreachedBar) { 251 | canvas.drawRect(mUnreachedRectF, mUnreachedBarPaint); 252 | } 253 | 254 | if (mIfDrawText) 255 | canvas.drawText(mCurrentDrawText, mDrawTextStart, mDrawTextEnd, mTextPaint); 256 | } 257 | 258 | private void initializePainters() { 259 | mReachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 260 | mReachedBarPaint.setColor(mReachedBarColor); 261 | 262 | mUnreachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 263 | mUnreachedBarPaint.setColor(mUnreachedBarColor); 264 | 265 | mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 266 | mTextPaint.setColor(mTextColor); 267 | mTextPaint.setTextSize(mTextSize); 268 | } 269 | 270 | 271 | private void calculateDrawRectFWithoutProgressText() { 272 | mReachedRectF.left = getPaddingLeft(); 273 | mReachedRectF.top = getHeight() / 2.0f - mReachedBarHeight / 2.0f; 274 | mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) / (getMax() * 1.0f) * getProgress() + getPaddingLeft(); 275 | mReachedRectF.bottom = getHeight() / 2.0f + mReachedBarHeight / 2.0f; 276 | 277 | mUnreachedRectF.left = mReachedRectF.right; 278 | mUnreachedRectF.right = getWidth() - getPaddingRight(); 279 | mUnreachedRectF.top = getHeight() / 2.0f + -mUnreachedBarHeight / 2.0f; 280 | mUnreachedRectF.bottom = getHeight() / 2.0f + mUnreachedBarHeight / 2.0f; 281 | } 282 | 283 | private void calculateDrawRectF() { 284 | 285 | mCurrentDrawText = String.format("%d", getProgress() * 100 / getMax()); 286 | mCurrentDrawText = mPrefix + mCurrentDrawText + mSuffix; 287 | mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText); 288 | 289 | if (getProgress() == 0) { 290 | mDrawReachedBar = false; 291 | mDrawTextStart = getPaddingLeft(); 292 | } else { 293 | mDrawReachedBar = true; 294 | mReachedRectF.left = getPaddingLeft(); 295 | mReachedRectF.top = getHeight() / 2.0f - mReachedBarHeight / 2.0f; 296 | mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) / (getMax() * 1.0f) * getProgress() - mOffset + getPaddingLeft(); 297 | mReachedRectF.bottom = getHeight() / 2.0f + mReachedBarHeight / 2.0f; 298 | mDrawTextStart = (mReachedRectF.right + mOffset); 299 | } 300 | 301 | mDrawTextEnd = (int) ((getHeight() / 2.0f) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2.0f)); 302 | 303 | if ((mDrawTextStart + mDrawTextWidth) >= getWidth() - getPaddingRight()) { 304 | mDrawTextStart = getWidth() - getPaddingRight() - mDrawTextWidth; 305 | mReachedRectF.right = mDrawTextStart - mOffset; 306 | } 307 | 308 | float unreachedBarStart = mDrawTextStart + mDrawTextWidth + mOffset; 309 | if (unreachedBarStart >= getWidth() - getPaddingRight()) { 310 | mDrawUnreachedBar = false; 311 | } else { 312 | mDrawUnreachedBar = true; 313 | mUnreachedRectF.left = unreachedBarStart; 314 | mUnreachedRectF.right = getWidth() - getPaddingRight(); 315 | mUnreachedRectF.top = getHeight() / 2.0f + -mUnreachedBarHeight / 2.0f; 316 | mUnreachedRectF.bottom = getHeight() / 2.0f + mUnreachedBarHeight / 2.0f; 317 | } 318 | } 319 | 320 | /** 321 | * Get progress text color. 322 | * 323 | * @return progress text color. 324 | */ 325 | public int getTextColor() { 326 | return mTextColor; 327 | } 328 | 329 | /** 330 | * Get progress text size. 331 | * 332 | * @return progress text size. 333 | */ 334 | public float getProgressTextSize() { 335 | return mTextSize; 336 | } 337 | 338 | public int getUnreachedBarColor() { 339 | return mUnreachedBarColor; 340 | } 341 | 342 | public int getReachedBarColor() { 343 | return mReachedBarColor; 344 | } 345 | 346 | public int getProgress() { 347 | return mCurrentProgress; 348 | } 349 | 350 | public int getMax() { 351 | return mMaxProgress; 352 | } 353 | 354 | public float getReachedBarHeight() { 355 | return mReachedBarHeight; 356 | } 357 | 358 | public float getUnreachedBarHeight() { 359 | return mUnreachedBarHeight; 360 | } 361 | 362 | public void setProgressTextSize(float textSize) { 363 | this.mTextSize = textSize; 364 | mTextPaint.setTextSize(mTextSize); 365 | invalidate(); 366 | } 367 | 368 | public void setProgressTextColor(int textColor) { 369 | this.mTextColor = textColor; 370 | mTextPaint.setColor(mTextColor); 371 | invalidate(); 372 | } 373 | 374 | public void setUnreachedBarColor(int barColor) { 375 | this.mUnreachedBarColor = barColor; 376 | mUnreachedBarPaint.setColor(mUnreachedBarColor); 377 | invalidate(); 378 | } 379 | 380 | public void setReachedBarColor(int progressColor) { 381 | this.mReachedBarColor = progressColor; 382 | mReachedBarPaint.setColor(mReachedBarColor); 383 | invalidate(); 384 | } 385 | 386 | public void setReachedBarHeight(float height) { 387 | mReachedBarHeight = height; 388 | } 389 | 390 | public void setUnreachedBarHeight(float height) { 391 | mUnreachedBarHeight = height; 392 | } 393 | 394 | public void setMax(int maxProgress) { 395 | if (maxProgress > 0) { 396 | this.mMaxProgress = maxProgress; 397 | invalidate(); 398 | } 399 | } 400 | 401 | public void setSuffix(String suffix) { 402 | if (suffix == null) { 403 | mSuffix = ""; 404 | } else { 405 | mSuffix = suffix; 406 | } 407 | } 408 | 409 | public String getSuffix() { 410 | return mSuffix; 411 | } 412 | 413 | public void setPrefix(String prefix) { 414 | if (prefix == null) 415 | mPrefix = ""; 416 | else { 417 | mPrefix = prefix; 418 | } 419 | } 420 | 421 | public String getPrefix() { 422 | return mPrefix; 423 | } 424 | 425 | public void incrementProgressBy(int by) { 426 | if (by > 0) { 427 | setProgress(getProgress() + by); 428 | } 429 | 430 | if(mListener != null){ 431 | mListener.onProgressChange(getProgress(), getMax()); 432 | } 433 | } 434 | 435 | public void setProgress(int progress) { 436 | if (progress <= getMax() && progress >= 0) { 437 | this.mCurrentProgress = progress; 438 | invalidate(); 439 | } 440 | } 441 | 442 | @Override 443 | protected Parcelable onSaveInstanceState() { 444 | final Bundle bundle = new Bundle(); 445 | bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState()); 446 | bundle.putInt(INSTANCE_TEXT_COLOR, getTextColor()); 447 | bundle.putFloat(INSTANCE_TEXT_SIZE, getProgressTextSize()); 448 | bundle.putFloat(INSTANCE_REACHED_BAR_HEIGHT, getReachedBarHeight()); 449 | bundle.putFloat(INSTANCE_UNREACHED_BAR_HEIGHT, getUnreachedBarHeight()); 450 | bundle.putInt(INSTANCE_REACHED_BAR_COLOR, getReachedBarColor()); 451 | bundle.putInt(INSTANCE_UNREACHED_BAR_COLOR, getUnreachedBarColor()); 452 | bundle.putInt(INSTANCE_MAX, getMax()); 453 | bundle.putInt(INSTANCE_PROGRESS, getProgress()); 454 | bundle.putString(INSTANCE_SUFFIX, getSuffix()); 455 | bundle.putString(INSTANCE_PREFIX, getPrefix()); 456 | bundle.putBoolean(INSTANCE_TEXT_VISIBILITY, getProgressTextVisibility()); 457 | return bundle; 458 | } 459 | 460 | @Override 461 | protected void onRestoreInstanceState(Parcelable state) { 462 | if (state instanceof Bundle) { 463 | final Bundle bundle = (Bundle) state; 464 | mTextColor = bundle.getInt(INSTANCE_TEXT_COLOR); 465 | mTextSize = bundle.getFloat(INSTANCE_TEXT_SIZE); 466 | mReachedBarHeight = bundle.getFloat(INSTANCE_REACHED_BAR_HEIGHT); 467 | mUnreachedBarHeight = bundle.getFloat(INSTANCE_UNREACHED_BAR_HEIGHT); 468 | mReachedBarColor = bundle.getInt(INSTANCE_REACHED_BAR_COLOR); 469 | mUnreachedBarColor = bundle.getInt(INSTANCE_UNREACHED_BAR_COLOR); 470 | initializePainters(); 471 | setMax(bundle.getInt(INSTANCE_MAX)); 472 | setProgress(bundle.getInt(INSTANCE_PROGRESS)); 473 | setPrefix(bundle.getString(INSTANCE_PREFIX)); 474 | setSuffix(bundle.getString(INSTANCE_SUFFIX)); 475 | setProgressTextVisibility(bundle.getBoolean(INSTANCE_TEXT_VISIBILITY) ? Visible : Invisible); 476 | super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE)); 477 | return; 478 | } 479 | super.onRestoreInstanceState(state); 480 | } 481 | 482 | public float dp2px(float dp) { 483 | final float scale = getResources().getDisplayMetrics().density; 484 | return dp * scale + 0.5f; 485 | } 486 | 487 | public float sp2px(float sp) { 488 | final float scale = getResources().getDisplayMetrics().scaledDensity; 489 | return sp * scale; 490 | } 491 | 492 | public void setProgressTextVisibility(ProgressTextVisibility visibility) { 493 | mIfDrawText = visibility == Visible; 494 | invalidate(); 495 | } 496 | 497 | public boolean getProgressTextVisibility() { 498 | return mIfDrawText; 499 | } 500 | 501 | public void setOnProgressBarListener(On listener){ 502 | mListener = listener; 503 | } 504 | } 505 | -------------------------------------------------------------------------------- /app/src/main/java/nico/styTool/plus/MaterialDialog.java: -------------------------------------------------------------------------------- 1 | package nico.styTool.plus; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.graphics.Color; 7 | import android.graphics.drawable.ColorDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Build; 10 | import android.view.Gravity; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.view.Window; 15 | import android.view.WindowManager; 16 | import android.view.inputmethod.InputMethodManager; 17 | import android.widget.AutoCompleteTextView; 18 | import android.widget.Button; 19 | import android.widget.EditText; 20 | import android.widget.LinearLayout; 21 | import android.widget.ListAdapter; 22 | import android.widget.ListView; 23 | import android.widget.TextView; 24 | 25 | /** 26 | * Created by drakeet on 9/28/14. 27 | */ 28 | public class MaterialDialog 29 | { 30 | 31 | private final static int BUTTON_BOTTOM = 9; 32 | private final static int BUTTON_TOP = 9; 33 | 34 | private boolean mCancel; 35 | private Context mContext; 36 | private AlertDialog mAlertDialog; 37 | private MaterialDialog.Builder mBuilder; 38 | private View mView; 39 | private int mTitleResId; 40 | private CharSequence mTitle; 41 | private int mMessageResId; 42 | private CharSequence mMessage; 43 | private Button mPositiveButton; 44 | private LinearLayout.LayoutParams mLayoutParams; 45 | private Button mNegativeButton; 46 | private boolean mHasShow = false; 47 | private int mBackgroundResId = -1; 48 | private Drawable mBackgroundDrawable; 49 | private View mMessageContentView; 50 | private int mMessageContentViewResId; 51 | private DialogInterface.OnDismissListener mOnDismissListener; 52 | private int pId = -1, nId = -1; 53 | private String pText, nText; 54 | View.OnClickListener pListener, nListener; 55 | 56 | 57 | public MaterialDialog(Context context) 58 | { 59 | this.mContext = context; 60 | } 61 | 62 | 63 | public void show() 64 | { 65 | if (!mHasShow) 66 | { 67 | mBuilder = new Builder(); 68 | } 69 | else 70 | { 71 | mAlertDialog.show(); 72 | } 73 | mHasShow = true; 74 | } 75 | 76 | 77 | public MaterialDialog setView(View view) 78 | { 79 | mView = view; 80 | if (mBuilder != null) 81 | { 82 | mBuilder.setView(view); 83 | } 84 | return this; 85 | } 86 | 87 | 88 | public MaterialDialog setContentView(View view) 89 | { 90 | mMessageContentView = view; 91 | mMessageContentViewResId = 0; 92 | if (mBuilder != null) 93 | { 94 | mBuilder.setContentView(mMessageContentView); 95 | } 96 | return this; 97 | } 98 | 99 | 100 | /** 101 | * Set a custom view resource to be the contents of the dialog. 102 | * 103 | * @param layoutResId resource ID to be inflated 104 | */ 105 | public MaterialDialog setContentView(int layoutResId) 106 | { 107 | mMessageContentViewResId = layoutResId; 108 | mMessageContentView = null; 109 | if (mBuilder != null) 110 | { 111 | mBuilder.setContentView(layoutResId); 112 | } 113 | return this; 114 | } 115 | 116 | 117 | public MaterialDialog setBackground(Drawable drawable) 118 | { 119 | mBackgroundDrawable = drawable; 120 | if (mBuilder != null) 121 | { 122 | mBuilder.setBackground(mBackgroundDrawable); 123 | } 124 | return this; 125 | } 126 | 127 | 128 | public MaterialDialog setBackgroundResource(int resId) 129 | { 130 | mBackgroundResId = resId; 131 | if (mBuilder != null) 132 | { 133 | mBuilder.setBackgroundResource(mBackgroundResId); 134 | } 135 | return this; 136 | } 137 | 138 | 139 | public void dismiss() 140 | { 141 | mAlertDialog.dismiss(); 142 | } 143 | 144 | 145 | private int dip2px(float dpValue) 146 | { 147 | final float scale = mContext.getResources().getDisplayMetrics().density; 148 | return (int) (dpValue * scale + 0.5f); 149 | } 150 | 151 | 152 | private static boolean isLollipop() 153 | { 154 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; 155 | } 156 | 157 | 158 | public MaterialDialog setTitle(int resId) 159 | { 160 | mTitleResId = resId; 161 | if (mBuilder != null) 162 | { 163 | mBuilder.setTitle(resId); 164 | } 165 | return this; 166 | } 167 | 168 | 169 | public MaterialDialog setTitle(CharSequence title) 170 | { 171 | mTitle = title; 172 | if (mBuilder != null) 173 | { 174 | mBuilder.setTitle(title); 175 | } 176 | return this; 177 | } 178 | 179 | 180 | public MaterialDialog setMessage(int resId) 181 | { 182 | mMessageResId = resId; 183 | if (mBuilder != null) 184 | { 185 | mBuilder.setMessage(resId); 186 | } 187 | return this; 188 | } 189 | 190 | 191 | public MaterialDialog setMessage(CharSequence message) 192 | { 193 | mMessage = message; 194 | if (mBuilder != null) 195 | { 196 | mBuilder.setMessage(message); 197 | } 198 | return this; 199 | } 200 | 201 | 202 | public MaterialDialog setPositiveButton(int resId, final View.OnClickListener listener) 203 | { 204 | this.pId = resId; 205 | this.pListener = listener; 206 | return this; 207 | } 208 | 209 | 210 | public Button getPositiveButton() 211 | { 212 | return mPositiveButton; 213 | } 214 | 215 | 216 | public Button getNegativeButton() 217 | { 218 | return mNegativeButton; 219 | } 220 | 221 | 222 | public MaterialDialog setPositiveButton(String text, final View.OnClickListener listener) 223 | { 224 | this.pText = text; 225 | this.pListener = listener; 226 | return this; 227 | } 228 | 229 | 230 | public MaterialDialog setNegativeButton(int resId, final View.OnClickListener listener) 231 | { 232 | this.nId = resId; 233 | this.nListener = listener; 234 | return this; 235 | } 236 | 237 | 238 | public MaterialDialog setNegativeButton(String text, final View.OnClickListener listener) 239 | { 240 | this.nText = text; 241 | this.nListener = listener; 242 | return this; 243 | } 244 | 245 | 246 | /** 247 | * Sets whether this dialog is canceled when touched outside the window's 248 | * bounds OR pressed the back key. If setting to true, the dialog is 249 | * set to be cancelable if not 250 | * already set. 251 | * 252 | * @param cancel Whether the dialog should be canceled when touched outside 253 | * the window OR pressed the back key. 254 | */ 255 | public MaterialDialog setCanceledOnTouchOutside(boolean cancel) 256 | { 257 | this.mCancel = cancel; 258 | if (mBuilder != null) 259 | { 260 | mBuilder.setCanceledOnTouchOutside(mCancel); 261 | } 262 | return this; 263 | } 264 | 265 | 266 | public MaterialDialog setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) 267 | { 268 | this.mOnDismissListener = onDismissListener; 269 | return this; 270 | } 271 | 272 | 273 | private class Builder 274 | { 275 | 276 | private TextView mTitleView; 277 | private ViewGroup mMessageContentRoot; 278 | private TextView mMessageView; 279 | private Window mAlertDialogWindow; 280 | private LinearLayout mButtonLayout; 281 | 282 | 283 | private Builder() 284 | { 285 | mAlertDialog = new AlertDialog.Builder(mContext).create(); 286 | mAlertDialog.show(); 287 | 288 | mAlertDialog.getWindow() 289 | .clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 290 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 291 | mAlertDialog.getWindow() 292 | .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE); 293 | 294 | mAlertDialogWindow = mAlertDialog.getWindow(); 295 | mAlertDialogWindow.setBackgroundDrawable( 296 | new ColorDrawable(android.graphics.Color.TRANSPARENT)); 297 | 298 | View contentView = LayoutInflater.from(mContext) 299 | .inflate(R.layout.layout_material_dialog, null); 300 | contentView.setFocusable(true); 301 | contentView.setFocusableInTouchMode(true); 302 | 303 | mAlertDialogWindow.setBackgroundDrawableResource(R.drawable.material_dialog_window); 304 | 305 | mAlertDialogWindow.setContentView(contentView); 306 | 307 | mTitleView = (TextView) mAlertDialogWindow.findViewById(R.id.title); 308 | mMessageView = (TextView) mAlertDialogWindow.findViewById(R.id.message); 309 | mButtonLayout = (LinearLayout) mAlertDialogWindow.findViewById(R.id.buttonLayout); 310 | mPositiveButton = (Button) mButtonLayout.findViewById(R.id.btn_p); 311 | mNegativeButton = (Button) mButtonLayout.findViewById(R.id.btn_n); 312 | mMessageContentRoot = (ViewGroup) mAlertDialogWindow.findViewById( 313 | R.id.message_content_root); 314 | if (mView != null) 315 | { 316 | LinearLayout linearLayout = (LinearLayout) mAlertDialogWindow.findViewById( 317 | R.id.contentView); 318 | linearLayout.removeAllViews(); 319 | linearLayout.addView(mView); 320 | } 321 | if (mTitleResId != 0) 322 | { 323 | setTitle(mTitleResId); 324 | } 325 | if (mTitle != null) 326 | { 327 | setTitle(mTitle); 328 | } 329 | if (mTitle == null && mTitleResId == 0) 330 | { 331 | mTitleView.setVisibility(View.GONE); 332 | } 333 | if (mMessageResId != 0) 334 | { 335 | setMessage(mMessageResId); 336 | } 337 | if (mMessage != null) 338 | { 339 | setMessage(mMessage); 340 | } 341 | if (pId != -1) 342 | { 343 | mPositiveButton.setVisibility(View.VISIBLE); 344 | mPositiveButton.setText(pId); 345 | mPositiveButton.setOnClickListener(pListener); 346 | if (isLollipop()) 347 | { 348 | mPositiveButton.setElevation(0); 349 | } 350 | } 351 | if (nId != -1) 352 | { 353 | mNegativeButton.setVisibility(View.VISIBLE); 354 | mNegativeButton.setText(nId); 355 | mNegativeButton.setOnClickListener(nListener); 356 | if (isLollipop()) 357 | { 358 | mNegativeButton.setElevation(0); 359 | } 360 | } 361 | if (!isNullOrEmpty(pText)) 362 | { 363 | mPositiveButton.setVisibility(View.VISIBLE); 364 | mPositiveButton.setText(pText); 365 | mPositiveButton.setOnClickListener(pListener); 366 | if (isLollipop()) 367 | { 368 | mPositiveButton.setElevation(0); 369 | } 370 | } 371 | 372 | if (!isNullOrEmpty(nText)) 373 | { 374 | mNegativeButton.setVisibility(View.VISIBLE); 375 | mNegativeButton.setText(nText); 376 | mNegativeButton.setOnClickListener(nListener); 377 | if (isLollipop()) 378 | { 379 | mNegativeButton.setElevation(0); 380 | } 381 | } 382 | if (isNullOrEmpty(pText) && pId == -1) 383 | { 384 | mPositiveButton.setVisibility(View.GONE); 385 | } 386 | if (isNullOrEmpty(nText) && nId == -1) 387 | { 388 | mNegativeButton.setVisibility(View.GONE); 389 | } 390 | if (mBackgroundResId != -1) 391 | { 392 | LinearLayout linearLayout = (LinearLayout) mAlertDialogWindow.findViewById( 393 | R.id.material_background); 394 | linearLayout.setBackgroundResource(mBackgroundResId); 395 | } 396 | if (mBackgroundDrawable != null) 397 | { 398 | LinearLayout linearLayout = (LinearLayout) mAlertDialogWindow.findViewById( 399 | R.id.material_background); 400 | linearLayout.setBackground(mBackgroundDrawable); 401 | } 402 | 403 | if (mMessageContentView != null) 404 | { 405 | this.setContentView(mMessageContentView); 406 | } 407 | else if (mMessageContentViewResId != 0) 408 | { 409 | this.setContentView(mMessageContentViewResId); 410 | } 411 | mAlertDialog.setCanceledOnTouchOutside(mCancel); 412 | mAlertDialog.setCancelable(mCancel); 413 | if (mOnDismissListener != null) 414 | { 415 | mAlertDialog.setOnDismissListener(mOnDismissListener); 416 | } 417 | } 418 | 419 | 420 | public void setTitle(int resId) 421 | { 422 | mTitleView.setText(resId); 423 | } 424 | 425 | 426 | public void setTitle(CharSequence title) 427 | { 428 | mTitleView.setText(title); 429 | } 430 | 431 | 432 | public void setMessage(int resId) 433 | { 434 | if (mMessageView != null) 435 | { 436 | mMessageView.setText(resId); 437 | } 438 | } 439 | 440 | 441 | public void setMessage(CharSequence message) 442 | { 443 | if (mMessageView != null) 444 | { 445 | mMessageView.setText(message); 446 | } 447 | } 448 | 449 | 450 | /** 451 | * set positive button 452 | * 453 | * @param text the name of button 454 | */ 455 | public void setPositiveButton(String text, final View.OnClickListener listener) 456 | { 457 | Button button = new Button(mContext); 458 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( 459 | LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); 460 | button.setLayoutParams(params); 461 | button.setBackgroundResource(R.drawable.material_card); 462 | button.setTextColor(Color.argb(255, 35, 159, 242)); 463 | button.setText(text); 464 | button.setGravity(Gravity.CENTER); 465 | button.setTextSize(14); 466 | button.setPadding(dip2px(12), 0, dip2px(32), dip2px(BUTTON_BOTTOM)); 467 | button.setOnClickListener(listener); 468 | mButtonLayout.addView(button); 469 | } 470 | 471 | 472 | /** 473 | * set negative button 474 | * 475 | * @param text the name of button 476 | */ 477 | public void setNegativeButton(String text, final View.OnClickListener listener) 478 | { 479 | Button button = new Button(mContext); 480 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( 481 | LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); 482 | button.setLayoutParams(params); 483 | button.setBackgroundResource(R.drawable.material_card); 484 | button.setText(text); 485 | button.setTextColor(Color.argb(222, 0, 0, 0)); 486 | button.setTextSize(14); 487 | button.setGravity(Gravity.CENTER); 488 | button.setPadding(0, 0, 0, dip2px(8)); 489 | button.setOnClickListener(listener); 490 | if (mButtonLayout.getChildCount() > 0) 491 | { 492 | params.setMargins(20, 0, 10, dip2px(BUTTON_BOTTOM)); 493 | button.setLayoutParams(params); 494 | mButtonLayout.addView(button, 1); 495 | } 496 | else 497 | { 498 | button.setLayoutParams(params); 499 | mButtonLayout.addView(button); 500 | } 501 | } 502 | 503 | 504 | public void setView(View view) 505 | { 506 | LinearLayout l = (LinearLayout) mAlertDialogWindow.findViewById(R.id.contentView); 507 | l.removeAllViews(); 508 | ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams( 509 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 510 | view.setLayoutParams(layoutParams); 511 | 512 | view.setOnFocusChangeListener(new View.OnFocusChangeListener() { 513 | @Override public void onFocusChange(View v, boolean hasFocus) 514 | { 515 | mAlertDialogWindow.setSoftInputMode( 516 | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); 517 | // show imm 518 | InputMethodManager imm = (InputMethodManager) mContext.getSystemService( 519 | Context.INPUT_METHOD_SERVICE); 520 | imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 521 | InputMethodManager.HIDE_IMPLICIT_ONLY); 522 | } 523 | }); 524 | 525 | l.addView(view); 526 | 527 | if (view instanceof ViewGroup) 528 | { 529 | 530 | ViewGroup viewGroup = (ViewGroup) view; 531 | 532 | for (int i = 0; i < viewGroup.getChildCount(); i++) 533 | { 534 | if (viewGroup.getChildAt(i) instanceof EditText) 535 | { 536 | EditText editText = (EditText) viewGroup.getChildAt(i); 537 | editText.setFocusable(true); 538 | editText.requestFocus(); 539 | editText.setFocusableInTouchMode(true); 540 | } 541 | } 542 | for (int i = 0; i < viewGroup.getChildCount(); i++) 543 | { 544 | if (viewGroup.getChildAt(i) instanceof AutoCompleteTextView) 545 | { 546 | AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) viewGroup 547 | .getChildAt(i); 548 | autoCompleteTextView.setFocusable(true); 549 | autoCompleteTextView.requestFocus(); 550 | autoCompleteTextView.setFocusableInTouchMode(true); 551 | } 552 | } 553 | } 554 | } 555 | 556 | 557 | public void setContentView(View contentView) 558 | { 559 | ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams( 560 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 561 | contentView.setLayoutParams(layoutParams); 562 | if (contentView instanceof ListView) 563 | { 564 | setListViewHeightBasedOnChildren((ListView) contentView); 565 | } 566 | LinearLayout linearLayout = (LinearLayout) mAlertDialogWindow.findViewById( 567 | R.id.message_content_view); 568 | if (linearLayout != null) 569 | { 570 | linearLayout.removeAllViews(); 571 | linearLayout.addView(contentView); 572 | } 573 | for (int i = 0; i < (linearLayout != null ? linearLayout.getChildCount() : 0); i++) 574 | { 575 | if (linearLayout.getChildAt(i) instanceof AutoCompleteTextView) 576 | { 577 | AutoCompleteTextView autoCompleteTextView 578 | = (AutoCompleteTextView) linearLayout.getChildAt(i); 579 | autoCompleteTextView.setFocusable(true); 580 | autoCompleteTextView.requestFocus(); 581 | autoCompleteTextView.setFocusableInTouchMode(true); 582 | } 583 | } 584 | } 585 | 586 | 587 | /** 588 | * Set a custom view resource to be the contents of the dialog. The 589 | * resource will be inflated into a ScrollView. 590 | * 591 | * @param layoutResId resource ID to be inflated 592 | */ 593 | public void setContentView(int layoutResId) 594 | { 595 | mMessageContentRoot.removeAllViews(); 596 | // Not setting this to the other content view because user has defined their own 597 | // layout params, and we don't want to overwrite those. 598 | LayoutInflater.from(mMessageContentRoot.getContext()) 599 | .inflate(layoutResId, mMessageContentRoot); 600 | } 601 | 602 | 603 | public void setBackground(Drawable drawable) 604 | { 605 | LinearLayout linearLayout = (LinearLayout) mAlertDialogWindow.findViewById( 606 | R.id.material_background); 607 | linearLayout.setBackground(drawable); 608 | } 609 | 610 | 611 | public void setBackgroundResource(int resId) 612 | { 613 | LinearLayout linearLayout = (LinearLayout) mAlertDialogWindow.findViewById( 614 | R.id.material_background); 615 | linearLayout.setBackgroundResource(resId); 616 | } 617 | 618 | 619 | public void setCanceledOnTouchOutside(boolean canceledOnTouchOutside) 620 | { 621 | mAlertDialog.setCanceledOnTouchOutside(canceledOnTouchOutside); 622 | mAlertDialog.setCancelable(canceledOnTouchOutside); 623 | } 624 | } 625 | 626 | 627 | private boolean isNullOrEmpty(String nText) 628 | { 629 | return nText == null || nText.isEmpty(); 630 | } 631 | 632 | 633 | private void setListViewHeightBasedOnChildren(ListView listView) 634 | { 635 | ListAdapter listAdapter = listView.getAdapter(); 636 | if (listAdapter == null) 637 | { 638 | // pre-condition 639 | return; 640 | } 641 | 642 | int totalHeight = 0; 643 | for (int i = 0; i < listAdapter.getCount(); i++) 644 | { 645 | View listItem = listAdapter.getView(i, null, listView); 646 | listItem.measure(0, 0); 647 | totalHeight += listItem.getMeasuredHeight(); 648 | } 649 | 650 | ViewGroup.LayoutParams params = listView.getLayoutParams(); 651 | params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); 652 | listView.setLayoutParams(params); 653 | } 654 | } 655 | 656 | -------------------------------------------------------------------------------- /app/src/main/java/nico/styTool/plus/SlideBottomPanel.java: -------------------------------------------------------------------------------- 1 | package nico.styTool.plus; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ValueAnimator; 5 | import android.app.Application; 6 | import android.content.Context; 7 | import android.content.res.TypedArray; 8 | import android.os.Build; 9 | import android.util.AttributeSet; 10 | import android.view.LayoutInflater; 11 | import android.view.MotionEvent; 12 | import android.view.VelocityTracker; 13 | import android.view.View; 14 | import android.view.ViewConfiguration; 15 | import android.view.ViewGroup; 16 | import android.view.animation.AccelerateInterpolator; 17 | import android.view.animation.Interpolator; 18 | import android.widget.AbsListView; 19 | import android.widget.FrameLayout; 20 | import android.widget.ScrollView; 21 | 22 | import com.nineoldandroids.animation.ObjectAnimator; 23 | import com.nineoldandroids.view.ViewHelper; 24 | 25 | /** 26 | * Created by NeXT on 15/8/3. 27 | */ 28 | public class SlideBottomPanel extends FrameLayout { 29 | 30 | private static final int TAG_BACKGROUND = 1; 31 | private static final int TAG_PANEL = 2; 32 | 33 | private static final int DEFAULT_BACKGROUND_ID = -1; 34 | private static final int DEFAULT_TITLE_HEIGHT_NO_DISPLAY = 60; 35 | private static final int DEFAULT_PANEL_HEIGHT = 380; 36 | private static final int DEFAULT_MOVE_DISTANCE_TO_TRIGGER = 30; 37 | private static final int DEFAULT_ANIMATION_DURATION = 250; 38 | private static final int MAX_CLICK_TIME = 300; 39 | private static final boolean DEFAULT_FADE = true; 40 | private static final boolean DEFAULT_BOUNDARY = true; 41 | private static final boolean DEFAULT_HIDE_PANEL_TITLE = false; 42 | 43 | private static float MAX_CLICK_DISTANCE = 5; 44 | 45 | private int mChildCount; 46 | private float mDensity; 47 | private boolean isAnimating = false; 48 | private boolean isPanelShowing = false; 49 | 50 | private float xVelocity; 51 | private float yVelocity; 52 | private float mTouchSlop; 53 | private int mMaxVelocity; 54 | private int mMinVelocity; 55 | private VelocityTracker mVelocityTracker; 56 | 57 | private int mMeasureHeight; 58 | private float firstDownX; 59 | private float firstDownY; 60 | private float downY; 61 | private float deltaY; 62 | private long mPressStartTime; 63 | private boolean isDragging = false; 64 | 65 | private int mBackgroundId; 66 | private float mPanelHeight; 67 | private float mTitleHeightNoDisplay; 68 | private float mMoveDistanceToTrigger; 69 | private int mAnimationDuration; 70 | private boolean mIsFade = true; 71 | private boolean mBoundary = true; 72 | private boolean mHidePanelTitle = false; 73 | private boolean isPanelOnTouch = false; 74 | 75 | private Interpolator mOpenAnimationInterpolator = new AccelerateInterpolator(); 76 | private Interpolator mCloseAnimationInterpolator = new AccelerateInterpolator(); 77 | 78 | private Context mContext; 79 | private DarkFrameLayout mDarkFrameLayout; 80 | 81 | public SlideBottomPanel(Context context) { 82 | this(context, null); 83 | } 84 | 85 | public SlideBottomPanel(Context context, AttributeSet attrs) { 86 | this(context, attrs, 0); 87 | } 88 | 89 | public SlideBottomPanel(Context context, AttributeSet attrs, int defStyleAttr) { 90 | super(context, attrs, defStyleAttr); 91 | 92 | mContext = context; 93 | mDensity = getResources().getDisplayMetrics().density; 94 | 95 | ViewConfiguration vc = ViewConfiguration.get(mContext); 96 | mMaxVelocity = vc.getScaledMaximumFlingVelocity(); 97 | mMinVelocity = vc.getScaledMinimumFlingVelocity(); 98 | mTouchSlop = vc.getScaledTouchSlop(); 99 | 100 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlideBottomPanel, defStyleAttr, 0); 101 | 102 | mBackgroundId = a.getResourceId(R.styleable.SlideBottomPanel_sbp_background_layout, DEFAULT_BACKGROUND_ID); 103 | mPanelHeight = a.getDimension(R.styleable.SlideBottomPanel_sbp_panel_height, dp2px(DEFAULT_PANEL_HEIGHT)); 104 | mBoundary = a.getBoolean(R.styleable.SlideBottomPanel_sbp_boundary, DEFAULT_BOUNDARY); 105 | MAX_CLICK_DISTANCE = mTitleHeightNoDisplay = a.getDimension(R.styleable.SlideBottomPanel_sbp_title_height_no_display,dp2px(DEFAULT_TITLE_HEIGHT_NO_DISPLAY)); 106 | mMoveDistanceToTrigger = a.getDimension(R.styleable.SlideBottomPanel_sbp_move_distance_trigger, dp2px(DEFAULT_MOVE_DISTANCE_TO_TRIGGER)); 107 | mAnimationDuration = a.getInt(R.styleable.SlideBottomPanel_sbp_animation_duration, DEFAULT_ANIMATION_DURATION); 108 | mHidePanelTitle = a.getBoolean(R.styleable.SlideBottomPanel_sbp_hide_panel_title, DEFAULT_HIDE_PANEL_TITLE); 109 | mIsFade = a.getBoolean(R.styleable.SlideBottomPanel_sbp_fade, DEFAULT_FADE); 110 | 111 | a.recycle(); 112 | 113 | initBackgroundView(); 114 | } 115 | 116 | @Override 117 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 118 | super.onLayout(changed, left, top, right, bottom); 119 | mChildCount = getChildCount(); 120 | int t = (int) (mMeasureHeight - mTitleHeightNoDisplay); 121 | for (int i = 0; i < mChildCount; i++) { 122 | View childView = getChildAt(i); 123 | if (childView.getTag() == null || (int) childView.getTag() != TAG_BACKGROUND) { 124 | childView.layout(0, t, childView.getMeasuredWidth(), childView.getMeasuredHeight() + t); 125 | childView.setTag(TAG_PANEL); 126 | // if (childView instanceof ViewGroup) { 127 | // ((ViewGroup)childView).setClipChildren(false); 128 | // } 129 | } else if (childView.getTag() == null){//空指计 130 | childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight()); 131 | childView.setPadding(0, 0, 0, (int)mTitleHeightNoDisplay); 132 | } 133 | } 134 | } 135 | 136 | @Override 137 | public boolean onInterceptTouchEvent(MotionEvent ev) { 138 | return isDragging; 139 | } 140 | 141 | @Override 142 | public boolean onTouchEvent(MotionEvent event) { 143 | return true; 144 | } 145 | 146 | @Override 147 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 148 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 149 | mMeasureHeight = getMeasuredHeight(); 150 | } 151 | 152 | @Override 153 | public boolean dispatchTouchEvent(MotionEvent ev) { 154 | initVelocityTracker(ev); 155 | boolean isConsume = false; 156 | switch (ev.getAction()) { 157 | case MotionEvent.ACTION_DOWN: 158 | isConsume = handleActionDown(ev); 159 | break; 160 | case MotionEvent.ACTION_MOVE: 161 | handleActionMove(ev); 162 | break; 163 | case MotionEvent.ACTION_UP: 164 | handleActionUp(ev); 165 | releaseVelocityTracker(); 166 | break; 167 | } 168 | return isConsume || super.dispatchTouchEvent(ev); 169 | } 170 | 171 | private void initBackgroundView() { 172 | if (mBackgroundId != -1) { 173 | mDarkFrameLayout = new DarkFrameLayout(mContext); 174 | mDarkFrameLayout.addView(LayoutInflater.from(mContext).inflate(mBackgroundId, null)); 175 | mDarkFrameLayout.setTag(TAG_BACKGROUND); 176 | mDarkFrameLayout.setSlideBottomPanel(this); 177 | addView(mDarkFrameLayout); 178 | } 179 | } 180 | 181 | private void handleActionUp(MotionEvent event) { 182 | if (!isPanelOnTouch) { 183 | return; 184 | } 185 | long pressDuration = System.currentTimeMillis() - mPressStartTime; 186 | computeVelocity(); 187 | if (!isPanelShowing && ((event.getY() - firstDownY) < 0 && (Math.abs(event.getY() - firstDownY) > mMoveDistanceToTrigger)) 188 | || (yVelocity < 0 && Math.abs(yVelocity) > Math.abs(xVelocity) && Math.abs(yVelocity) > mMinVelocity)) { 189 | displayPanel(); 190 | } else if (!isPanelShowing && pressDuration < MAX_CLICK_TIME && 191 | distance(firstDownX, firstDownY, event.getX(), event.getY()) < MAX_CLICK_DISTANCE) { 192 | displayPanel(); 193 | } else if (!isPanelShowing && isDragging && ((event.getY() - firstDownY > 0) || 194 | Math.abs(event.getY() - firstDownY) < mMoveDistanceToTrigger)){ 195 | hidePanel(); 196 | } 197 | 198 | if (isPanelShowing) { 199 | View mPanel = findViewWithTag(TAG_PANEL); 200 | float currentY = ViewHelper.getY(mPanel); 201 | if (currentY < (mMeasureHeight - mPanelHeight) || 202 | currentY < (mMeasureHeight - mPanelHeight + mMoveDistanceToTrigger)) { 203 | ObjectAnimator.ofFloat(mPanel, "y", currentY, mMeasureHeight - mPanelHeight) 204 | .setDuration(mAnimationDuration).start(); 205 | } else if (currentY > mMeasureHeight - mPanelHeight + mMoveDistanceToTrigger){ 206 | hidePanel(); 207 | } 208 | } 209 | 210 | isPanelOnTouch = false; 211 | isDragging = false; 212 | deltaY = 0; 213 | } 214 | 215 | private void handleActionMove(MotionEvent event) { 216 | if (!isPanelOnTouch) { 217 | return; 218 | } 219 | if (isPanelShowing && supportScrollInView((int) (firstDownY - event.getY()))) { 220 | return; 221 | } 222 | computeVelocity(); 223 | if (Math.abs(xVelocity) > Math.abs(yVelocity)) { 224 | return; 225 | } 226 | if (!isDragging && Math.abs(event.getY() - firstDownY) > mTouchSlop 227 | && Math.abs(event.getX() - firstDownX) < mTouchSlop) { 228 | isDragging = true; 229 | downY = event.getY(); 230 | } 231 | if (isDragging) { 232 | deltaY = event.getY() - downY; 233 | downY = event.getY(); 234 | 235 | View touchingView = findViewWithTag(TAG_PANEL); 236 | 237 | if (mHidePanelTitle && isPanelShowing) { 238 | hidePanelTitle(touchingView); 239 | } 240 | 241 | if (mDarkFrameLayout != null && mIsFade) { 242 | float currentY = ViewHelper.getY(touchingView); 243 | if (currentY > mMeasureHeight - mPanelHeight && 244 | currentY < mMeasureHeight - mTitleHeightNoDisplay) { 245 | mDarkFrameLayout.fade( 246 | (int) ((1 - currentY / (mMeasureHeight - mTitleHeightNoDisplay)) * DarkFrameLayout.MAX_ALPHA)); 247 | } 248 | } 249 | if (!mBoundary) { 250 | touchingView.offsetTopAndBottom((int) deltaY); 251 | } else { 252 | float touchingViewY = ViewHelper.getY(touchingView); 253 | if (touchingViewY + deltaY <= mMeasureHeight - mPanelHeight) { 254 | touchingView.offsetTopAndBottom((int) (mMeasureHeight - mPanelHeight - touchingViewY)); 255 | } else if (touchingViewY + deltaY >= mMeasureHeight - mTitleHeightNoDisplay) { 256 | touchingView.offsetTopAndBottom((int) (mMeasureHeight - mTitleHeightNoDisplay - touchingViewY)); 257 | } else { 258 | touchingView.offsetTopAndBottom((int) deltaY); 259 | } 260 | } 261 | } 262 | } 263 | 264 | private boolean handleActionDown(MotionEvent event) { 265 | boolean isConsume = false; 266 | mPressStartTime = System.currentTimeMillis(); 267 | firstDownX = event.getX(); 268 | firstDownY = downY = event.getY(); 269 | if (!isPanelShowing && downY > mMeasureHeight - mTitleHeightNoDisplay) { 270 | isPanelOnTouch = true; 271 | isConsume = true; 272 | } else if (!isPanelShowing && downY <= mMeasureHeight - mTitleHeightNoDisplay) { 273 | isPanelOnTouch = false; 274 | } else if (isPanelShowing && downY > mMeasureHeight - mPanelHeight) { 275 | isPanelOnTouch = true; 276 | } else if (isPanelShowing && downY < mMeasureHeight - mPanelHeight) { 277 | hidePanel(); 278 | isPanelOnTouch = false; 279 | } 280 | return isConsume; 281 | } 282 | 283 | private void hidePanel() { 284 | if (isAnimating) { 285 | return; 286 | } 287 | final View mPanel = findViewWithTag(TAG_PANEL); 288 | final int t = (int)(mMeasureHeight - mTitleHeightNoDisplay); 289 | ValueAnimator animator = ValueAnimator.ofFloat( 290 | ViewHelper.getY(mPanel), mMeasureHeight - mTitleHeightNoDisplay); 291 | animator.setInterpolator(mCloseAnimationInterpolator); 292 | animator.setTarget(mPanel); 293 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 294 | @Override 295 | public void onAnimationUpdate(ValueAnimator animation) { 296 | float value = (float) animation.getAnimatedValue(); 297 | ViewHelper.setY(mPanel, value); 298 | if (mDarkFrameLayout != null && mIsFade && value < t) { 299 | mDarkFrameLayout.fade((int) ((1 - value / t) * DarkFrameLayout.MAX_ALPHA)); 300 | } 301 | } 302 | }); 303 | animator.addListener(new Animator.AnimatorListener() { 304 | @Override 305 | public void onAnimationStart(Animator animation) { 306 | isAnimating = true; 307 | } 308 | 309 | @Override 310 | public void onAnimationEnd(Animator animation) { 311 | isAnimating = false; 312 | isPanelShowing = false; 313 | showPanelTitle(mPanel); 314 | } 315 | 316 | @Override 317 | public void onAnimationCancel(Animator animation) { 318 | isAnimating = false; 319 | isPanelShowing = false; 320 | showPanelTitle(mPanel); 321 | } 322 | 323 | @Override 324 | public void onAnimationRepeat(Animator animation) { 325 | } 326 | }); 327 | animator.start(); 328 | } 329 | 330 | public void displayPanel() { 331 | if (isPanelShowing || isAnimating) { 332 | return; 333 | } 334 | if (mIsFade || mDarkFrameLayout != null) { 335 | mDarkFrameLayout.fade(true); 336 | } 337 | final View mPanel = findViewWithTag(TAG_PANEL); 338 | ValueAnimator animator = ValueAnimator.ofFloat(ViewHelper.getY(mPanel), mMeasureHeight - mPanelHeight) 339 | .setDuration(mAnimationDuration); 340 | animator.setTarget(mPanel); 341 | animator.setInterpolator(mOpenAnimationInterpolator); 342 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 343 | @Override 344 | public void onAnimationUpdate(ValueAnimator animation) { 345 | float value = (float) animation.getAnimatedValue(); 346 | ViewHelper.setY(mPanel, value); 347 | if (mDarkFrameLayout != null && mIsFade 348 | && mDarkFrameLayout.getCurrentAlpha() != DarkFrameLayout.MAX_ALPHA) { 349 | mDarkFrameLayout.fade( 350 | (int) ((1 - value / (mMeasureHeight - mTitleHeightNoDisplay)) * DarkFrameLayout.MAX_ALPHA)); 351 | } 352 | } 353 | }); 354 | animator.addListener(new Animator.AnimatorListener() { 355 | @Override 356 | public void onAnimationStart(Animator animation) { 357 | isAnimating = true; 358 | } 359 | 360 | @Override 361 | public void onAnimationEnd(Animator animation) { 362 | isAnimating = false; 363 | } 364 | 365 | @Override 366 | public void onAnimationCancel(Animator animation) { 367 | isAnimating = false; 368 | } 369 | 370 | @Override 371 | public void onAnimationRepeat(Animator animation) { 372 | } 373 | }); 374 | animator.start(); 375 | isPanelShowing = true; 376 | hidePanelTitle(mPanel); 377 | } 378 | 379 | private void showPanelTitle(View panel) { 380 | if (panel instanceof ViewGroup && mHidePanelTitle) { 381 | try { 382 | View childView = ((ViewGroup) panel).getChildAt(1); 383 | if (childView.getVisibility() != View.VISIBLE) { 384 | childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight()); 385 | childView.setVisibility(View.VISIBLE); 386 | } 387 | } catch (NullPointerException e) { 388 | e.printStackTrace(); 389 | } 390 | } 391 | } 392 | 393 | private void hidePanelTitle(View panel) { 394 | if (panel instanceof ViewGroup && mHidePanelTitle) { 395 | try { 396 | ((ViewGroup) panel).getChildAt(1).setVisibility(View.INVISIBLE); 397 | } catch (NullPointerException e) { 398 | e.printStackTrace(); 399 | } 400 | } 401 | } 402 | 403 | public void hide() { 404 | if(!isPanelShowing) return; 405 | hidePanel(); 406 | } 407 | 408 | private void computeVelocity() { 409 | //units是单位表示, 1代表px/毫秒, 1000代表px/秒 410 | mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); 411 | xVelocity = mVelocityTracker.getXVelocity(); 412 | yVelocity = mVelocityTracker.getYVelocity(); 413 | } 414 | 415 | private boolean supportScrollInView(int direction) { 416 | 417 | View view = findViewWithTag(TAG_PANEL); 418 | if (view instanceof ViewGroup) { 419 | View childView = findTopChildUnder((ViewGroup) view, firstDownX, firstDownY); 420 | if (childView == null) { 421 | return false; 422 | } 423 | if (childView instanceof AbsListView) { 424 | AbsListView absListView = (AbsListView) childView; 425 | if (Build.VERSION.SDK_INT >= 19) { 426 | return absListView.canScrollList(direction); 427 | } else { 428 | return absListViewCanScrollList(absListView,direction); 429 | } 430 | } else if (childView instanceof ScrollView) { 431 | ScrollView scrollView = (ScrollView) childView; 432 | if (Build.VERSION.SDK_INT >= 14) { 433 | return scrollView.canScrollVertically(direction); 434 | } else { 435 | return scrollViewCanScrollVertically(scrollView, direction); 436 | } 437 | 438 | } else if (childView instanceof ViewGroup){ 439 | View grandchildView = findTopChildUnder((ViewGroup) childView, firstDownX, firstDownY); 440 | if (grandchildView == null) { 441 | return false; 442 | } 443 | if (grandchildView instanceof ViewGroup) { 444 | if (grandchildView instanceof AbsListView) { 445 | AbsListView absListView = (AbsListView) grandchildView; 446 | if (Build.VERSION.SDK_INT >= 19) { 447 | return absListView.canScrollList(direction); 448 | } else { 449 | return absListViewCanScrollList(absListView,direction); 450 | } 451 | } else if (grandchildView instanceof ScrollView) { 452 | ScrollView scrollView = (ScrollView) grandchildView; 453 | if (Build.VERSION.SDK_INT >= 14) { 454 | return scrollView.canScrollVertically(direction); 455 | } else { 456 | return scrollViewCanScrollVertically(scrollView, direction); 457 | } 458 | } 459 | } 460 | } 461 | 462 | 463 | } 464 | return false; 465 | } 466 | 467 | private View findTopChildUnder(ViewGroup parentView, float x, float y) { 468 | int childCount = parentView.getChildCount(); 469 | for (int i = childCount - 1; i >= 0; i--) { 470 | final View child = parentView.getChildAt(i); 471 | if (x >= child.getLeft() && x < child.getRight() && 472 | y >= child.getTop() + mMeasureHeight - mPanelHeight && 473 | y < child.getBottom() + mMeasureHeight - mPanelHeight) { 474 | return child; 475 | } 476 | } 477 | return null; 478 | } 479 | 480 | /** 481 | * Copy From ScrollView (API Level >= 14) 482 | * @param direction Negative to check scrolling up, positive to check 483 | * scrolling down. 484 | * @return true if the scrollView can be scrolled in the specified direction, 485 | * false otherwise 486 | */ 487 | private boolean scrollViewCanScrollVertically(ScrollView scrollView,int direction) { 488 | final int offset = Math.max(0, scrollView.getScrollY()); 489 | final int range = computeVerticalScrollRange(scrollView) - scrollView.getHeight(); 490 | if (range == 0) return false; 491 | if (direction < 0) { //scroll up 492 | return offset > 0; 493 | } else {//scroll down 494 | return offset < range - 1; 495 | } 496 | } 497 | 498 | /** 499 | * Copy From ScrollView (API Level >= 14) 500 | *
The scroll range of a scroll view is the overall height of all of its 501 | * children.
502 | */ 503 | private int computeVerticalScrollRange(ScrollView scrollView) { 504 | final int count = scrollView.getChildCount(); 505 | final int contentHeight = scrollView.getHeight() - scrollView.getPaddingBottom() - scrollView.getPaddingTop(); 506 | if (count == 0) { 507 | return contentHeight; 508 | } 509 | 510 | int scrollRange = scrollView.getChildAt(0).getBottom(); 511 | final int scrollY = scrollView.getScrollY(); 512 | final int overScrollBottom = Math.max(0, scrollRange - contentHeight); 513 | if (scrollY < 0) { 514 | scrollRange -= scrollY; 515 | } else if (scrollY > overScrollBottom) { 516 | scrollRange += scrollY - overScrollBottom; 517 | } 518 | 519 | return scrollRange; 520 | } 521 | 522 | /** 523 | * Copy From AbsListView (API Level >= 19) 524 | * @param absListView AbsListView 525 | * @param direction Negative to check scrolling up, positive to check 526 | * scrolling down. 527 | * @return true if the list can be scrolled in the specified direction, 528 | * false otherwise 529 | */ 530 | private boolean absListViewCanScrollList(AbsListView absListView,int direction) { 531 | final int childCount = absListView.getChildCount(); 532 | if (childCount == 0) { 533 | return false; 534 | } 535 | final int firstPosition = absListView.getFirstVisiblePosition(); 536 | if (direction > 0) {//can scroll down 537 | final int lastBottom = absListView.getChildAt(childCount - 1).getBottom(); 538 | final int lastPosition = firstPosition + childCount; 539 | return lastPosition < absListView.getCount() || lastBottom > absListView.getHeight() - absListView.getPaddingTop(); 540 | } else {//can scroll up 541 | final int firstTop = absListView.getChildAt(0).getTop(); 542 | return firstPosition > 0 || firstTop < absListView.getPaddingTop(); 543 | } 544 | } 545 | 546 | private void initVelocityTracker(MotionEvent event) { 547 | if (mVelocityTracker == null) { 548 | mVelocityTracker = VelocityTracker.obtain(); 549 | } 550 | mVelocityTracker.addMovement(event); 551 | } 552 | 553 | private void releaseVelocityTracker() { 554 | if (mVelocityTracker != null) { 555 | mVelocityTracker.clear(); 556 | mVelocityTracker.recycle(); 557 | mVelocityTracker = null; 558 | } 559 | } 560 | 561 | private double distance(float x1, float y1, float x2, float y2) { 562 | float deltaX = x1 - x2; 563 | float deltaY = y1 - y2; 564 | return Math.sqrt(deltaX * deltaX + deltaY * deltaY); 565 | } 566 | 567 | private int px2dp(int pxValue) { 568 | return (int) (pxValue / mDensity + 0.5f); 569 | } 570 | 571 | private int dp2px(int dpValue) { 572 | return (int) (dpValue * mDensity + 0.5f); 573 | } 574 | 575 | public boolean isPanelShowing() { 576 | return isPanelShowing; 577 | } 578 | } 579 | --------------------------------------------------------------------------------