瀏覽代碼

fab: use support library's rendering

Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
master
Eric Kuck 6 年之前
committed by Jason A. Donenfeld
父節點
當前提交
5463086e75
共有 19 個檔案被更改,包括 108 行新增640 行删除
  1. +0
    -1
      app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
  2. +0
    -97
      app/src/main/java/com/wireguard/android/widget/fab/AddFloatingActionButton.java
  3. +0
    -446
      app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButton.java
  4. +28
    -54
      app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java
  5. +55
    -0
      app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java
  6. +3
    -2
      app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java
  7. 二進制
     
  8. 二進制
     
  9. 二進制
     
  10. 二進制
     
  11. 二進制
     
  12. 二進制
     
  13. 二進制
     
  14. 二進制
     
  15. 二進制
     
  16. 二進制
     
  17. +9
    -0
      app/src/main/res/drawable/ic_action_add_inverse.xml
  18. +11
    -10
      app/src/main/res/layout/tunnel_list_fragment.xml
  19. +2
    -30
      app/src/main/res/values/fab.xml

+ 0
- 1
app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java 查看文件

@@ -35,7 +35,6 @@ import com.wireguard.android.databinding.TunnelListFragmentBinding;
import com.wireguard.android.databinding.TunnelListItemBinding;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.android.widget.ToggleSwitch;
import com.wireguard.config.Config;

import java.io.BufferedReader;


+ 0
- 97
app/src/main/java/com/wireguard/android/widget/fab/AddFloatingActionButton.java 查看文件

@@ -1,97 +0,0 @@
/*
* Copyright © 2014 Jerzy Chalupski
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget.fab;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;

import com.wireguard.android.R;

public class AddFloatingActionButton extends FloatingActionButton {
int mPlusColor;

public AddFloatingActionButton(final Context context) {
this(context, null);
}

public AddFloatingActionButton(final Context context, final AttributeSet attrs) {
super(context, attrs);
}

public AddFloatingActionButton(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}

@Override
void init(final Context context, final AttributeSet attributeSet) {
final TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.AddFloatingActionButton, 0, 0);
mPlusColor = attr.getColor(R.styleable.AddFloatingActionButton_fab_plusIconColor, FloatingActionButton.getColorFromTheme(context, android.R.attr.colorBackground, android.R.color.white));
attr.recycle();

super.init(context, attributeSet);
}

/**
* @return the current Color of plus icon.
*/
public int getPlusColor() {
return mPlusColor;
}

public void setPlusColor(final int color) {
if (mPlusColor != color) {
mPlusColor = color;
updateBackground();
}
}

public void setPlusColorResId(@ColorRes final int plusColor) {
setPlusColor(ContextCompat.getColor(getContext(), plusColor));
}

@Override
public void setIcon(@DrawableRes final int icon) {
throw new UnsupportedOperationException("Use FloatingActionButton if you want to use custom icon");
}

@Override
Drawable getIconDrawable() {
final float iconSize = getDimension(R.dimen.fab_icon_size);
final float iconHalfSize = iconSize / 2f;

final float plusSize = getDimension(R.dimen.fab_plus_icon_size);
final float plusHalfStroke = getDimension(R.dimen.fab_plus_icon_stroke) / 2f;
final float plusOffset = (iconSize - plusSize) / 2f;

final Shape shape = new Shape() {
@Override
public void draw(final Canvas canvas, final Paint paint) {
canvas.drawRect(plusOffset, iconHalfSize - plusHalfStroke, iconSize - plusOffset, iconHalfSize + plusHalfStroke, paint);
canvas.drawRect(iconHalfSize - plusHalfStroke, plusOffset, iconHalfSize + plusHalfStroke, iconSize - plusOffset, paint);
}
};

final ShapeDrawable drawable = new ShapeDrawable(shape);

final Paint paint = drawable.getPaint();
paint.setColor(mPlusColor);
paint.setStyle(Style.FILL);
paint.setAntiAlias(true);

return drawable;
}
}

+ 0
- 446
app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButton.java 查看文件

@@ -1,446 +0,0 @@
/*
* Copyright © 2014 Jerzy Chalupski
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget.fab;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.ShapeDrawable.ShaderFactory;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatImageButton;
import android.util.AttributeSet;
import android.widget.TextView;

import com.wireguard.android.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class FloatingActionButton extends AppCompatImageButton {

public static final int SIZE_NORMAL = 0;
public static final int SIZE_MINI = 1;
int mColorNormal;
int mColorPressed;
int mColorDisabled;
String mTitle;
boolean mStrokeVisible;
@DrawableRes
private int mIcon;
private Drawable mIconDrawable;
private int mSize;

private float mCircleSize;
private float mShadowRadius;
private float mShadowOffset;
private int mDrawableSize;
public FloatingActionButton(final Context context) {
this(context, null);
}

public FloatingActionButton(final Context context, final AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}

public FloatingActionButton(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}

public static int getColorFromTheme(final Context context, final int themeResource, @ColorRes final int fallback) {
final TypedArray a = context.obtainStyledAttributes(new int[]{themeResource});
try {
return a.getColor(0, ContextCompat.getColor(context, fallback));
} finally {
a.recycle();
}
}

void init(final Context context, final AttributeSet attributeSet) {
final TypedArray attr = context.obtainStyledAttributes(attributeSet,
R.styleable.FloatingActionButton, 0, 0);
mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal,
getColorFromTheme(context, android.R.attr.colorAccent, android.R.color.holo_blue_bright));
mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed,
darkenOrLightenColor(mColorNormal)); //TODO(msf): use getColorForState on the accent color from theme instead to get darker states
mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled,
ContextCompat.getColor(context, android.R.color.darker_gray)); //TODO(msf): load from theme
mSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL);
mIcon = attr.getResourceId(R.styleable.FloatingActionButton_fab_icon, 0);
mTitle = attr.getString(R.styleable.FloatingActionButton_fab_title);
mStrokeVisible = attr.getBoolean(R.styleable.FloatingActionButton_fab_stroke_visible, true);
attr.recycle();

updateCircleSize();
mShadowRadius = getDimension(R.dimen.fab_shadow_radius);
mShadowOffset = getDimension(R.dimen.fab_shadow_offset);
updateDrawableSize();

updateBackground();
}

private void updateDrawableSize() {
mDrawableSize = (int) (mCircleSize + 2 * mShadowRadius);
}

private void updateCircleSize() {
mCircleSize = getDimension(mSize == SIZE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini);
}

@FAB_SIZE
public int getSize() {
return mSize;
}

public void setSize(@FAB_SIZE final int size) {
if (size != SIZE_MINI && size != SIZE_NORMAL) {
throw new IllegalArgumentException("Use @FAB_SIZE constants only!");
}

if (mSize != size) {
mSize = size;
updateCircleSize();
updateDrawableSize();
updateBackground();
}
}

public void setIcon(@DrawableRes final int icon) {
if (mIcon != icon) {
mIcon = icon;
mIconDrawable = null;
updateBackground();
}
}

/**
* @return the current Color for normal state.
*/
public int getColorNormal() {
return mColorNormal;
}

public void setColorNormal(final int color) {
if (mColorNormal != color) {
mColorNormal = color;
updateBackground();
}
}

public void setColorNormalResId(@ColorRes final int colorNormal) {
setColorNormal(ContextCompat.getColor(getContext(), colorNormal));
}

/**
* @return the current color for pressed state.
*/
public int getColorPressed() {
return mColorPressed;
}

public void setColorPressed(final int color) {
if (mColorPressed != color) {
mColorPressed = color;
updateBackground();
}
}

public void setColorPressedResId(@ColorRes final int colorPressed) {
setColorPressed(ContextCompat.getColor(getContext(), colorPressed));
}

/**
* @return the current color for disabled state.
*/
public int getColorDisabled() {
return mColorDisabled;
}

public void setColorDisabled(final int color) {
if (mColorDisabled != color) {
mColorDisabled = color;
updateBackground();
}
}

public void setColorDisabledResId(@ColorRes final int colorDisabled) {
setColorDisabled(ContextCompat.getColor(getContext(), colorDisabled));
}

public boolean isStrokeVisible() {
return mStrokeVisible;
}

public void setStrokeVisible(final boolean visible) {
if (mStrokeVisible != visible) {
mStrokeVisible = visible;
updateBackground();
}
}

float getDimension(@DimenRes final int id) {
return getResources().getDimension(id);
}

TextView getLabelView() {
return (TextView) getTag(R.id.fab_label);
}

public String getTitle() {
return mTitle;
}

public void setTitle(final String title) {
mTitle = title;
final TextView label = getLabelView();
if (label != null) {
label.setText(title);
}
}

@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(mDrawableSize, mDrawableSize);
}

void updateBackground() {
final float strokeWidth = getDimension(R.dimen.fab_stroke_width);
final float halfStrokeWidth = strokeWidth / 2f;

final LayerDrawable layerDrawable = new LayerDrawable(
new Drawable[]{
//TODO(msf); replace these pngs with programatic elevation
getResources().getDrawable(mSize == SIZE_NORMAL ? R.drawable.fab_bg_normal : R.drawable.fab_bg_mini, null),
createFillDrawable(strokeWidth),
createOuterStrokeDrawable(strokeWidth),
getIconDrawable()
});

final int iconOffset = (int) (mCircleSize - getDimension(R.dimen.fab_icon_size)) / 2;

final int circleInsetHorizontal = (int) (mShadowRadius);
final int circleInsetTop = (int) (mShadowRadius - mShadowOffset);
final int circleInsetBottom = (int) (mShadowRadius + mShadowOffset);

layerDrawable.setLayerInset(1,
circleInsetHorizontal,
circleInsetTop,
circleInsetHorizontal,
circleInsetBottom);

layerDrawable.setLayerInset(2,
(int) (circleInsetHorizontal - halfStrokeWidth),
(int) (circleInsetTop - halfStrokeWidth),
(int) (circleInsetHorizontal - halfStrokeWidth),
(int) (circleInsetBottom - halfStrokeWidth));

layerDrawable.setLayerInset(3,
circleInsetHorizontal + iconOffset,
circleInsetTop + iconOffset,
circleInsetHorizontal + iconOffset,
circleInsetBottom + iconOffset);

setBackground(layerDrawable);
}

Drawable getIconDrawable() {
if (mIconDrawable != null) {
return mIconDrawable;
} else if (mIcon != 0) {
return ContextCompat.getDrawable(getContext(), mIcon);
} else {
return new ColorDrawable(Color.TRANSPARENT);
}
}

public void setIconDrawable(@NonNull final Drawable iconDrawable) {
if (mIconDrawable != iconDrawable) {
mIcon = 0;
mIconDrawable = iconDrawable;
updateBackground();
}
}

private StateListDrawable createFillDrawable(final float strokeWidth) {
final StateListDrawable drawable = new StateListDrawable();
drawable.addState(new int[]{-android.R.attr.state_enabled}, createCircleDrawable(mColorDisabled, strokeWidth));
drawable.addState(new int[]{android.R.attr.state_pressed}, createCircleDrawable(mColorPressed, strokeWidth));
drawable.addState(new int[]{}, createCircleDrawable(mColorNormal, strokeWidth));
return drawable;
}

private Drawable createCircleDrawable(final int color, final float strokeWidth) {
final int alpha = Color.alpha(color);
final int opaqueColor = opaque(color);

final ShapeDrawable fillDrawable = new ShapeDrawable(new OvalShape());

final Paint paint = fillDrawable.getPaint();
paint.setAntiAlias(true);
paint.setColor(opaqueColor);

final Drawable[] layers = {
fillDrawable,
createInnerStrokesDrawable(opaqueColor, strokeWidth)
};

final LayerDrawable drawable = alpha == 255 || !mStrokeVisible
? new LayerDrawable(layers)
: new TranslucentLayerDrawable(alpha, layers);

final int halfStrokeWidth = (int) (strokeWidth / 2f);
drawable.setLayerInset(1, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth);

return drawable;
}

private static Drawable createOuterStrokeDrawable(final float strokeWidth) {
final ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());

final Paint paint = shapeDrawable.getPaint();
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Style.STROKE);
paint.setColor(Color.BLACK);
paint.setAlpha(opacityToAlpha(0.02f));

return shapeDrawable;
}

private static int opacityToAlpha(final float opacity) {
return (int) (255f * opacity);
}

private static int darkenColor(final int argb) {
return adjustColorBrightness(argb, 0.9f);
}

private static int lightenColor(final int argb) {
return adjustColorBrightness(argb, 1.1f);
}

public static int darkenOrLightenColor(final int argb) {
final float[] hsv = new float[3];
Color.colorToHSV(argb, hsv);
final float factor;
if (hsv[2] < 0.2)
factor = 1.2f;
else
factor = 0.8f;

hsv[2] = Math.min(hsv[2] * factor, 1f);
return Color.HSVToColor(Color.alpha(argb), hsv);
}

private static int adjustColorBrightness(final int argb, final float factor) {
final float[] hsv = new float[3];
Color.colorToHSV(argb, hsv);

hsv[2] = Math.min(hsv[2] * factor, 1f);

return Color.HSVToColor(Color.alpha(argb), hsv);
}

private static int halfTransparent(final int argb) {
return Color.argb(
Color.alpha(argb) / 2,
Color.red(argb),
Color.green(argb),
Color.blue(argb)
);
}

private static int opaque(final int argb) {
return Color.rgb(
Color.red(argb),
Color.green(argb),
Color.blue(argb)
);
}

private Drawable createInnerStrokesDrawable(final int color, final float strokeWidth) {
if (!mStrokeVisible) {
return new ColorDrawable(Color.TRANSPARENT);
}

final ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());

final int bottomStrokeColor = darkenColor(color);
final int bottomStrokeColorHalfTransparent = halfTransparent(bottomStrokeColor);
final int topStrokeColor = lightenColor(color);
final int topStrokeColorHalfTransparent = halfTransparent(topStrokeColor);

final Paint paint = shapeDrawable.getPaint();
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Style.STROKE);
shapeDrawable.setShaderFactory(new ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new LinearGradient(width / 2, 0, width / 2, height,
new int[]{topStrokeColor, topStrokeColorHalfTransparent, color, bottomStrokeColorHalfTransparent, bottomStrokeColor},
new float[]{0f, 0.2f, 0.5f, 0.8f, 1f},
TileMode.CLAMP
);
}
});

return shapeDrawable;
}

@Override
public void setVisibility(final int visibility) {
final TextView label = getLabelView();
if (label != null) {
label.setVisibility(visibility);
}

super.setVisibility(visibility);
}

@Retention(RetentionPolicy.SOURCE)
@IntDef({SIZE_NORMAL, SIZE_MINI})
public @interface FAB_SIZE {
}

private static final class TranslucentLayerDrawable extends LayerDrawable {
private final int mAlpha;

private TranslucentLayerDrawable(final int alpha, final Drawable... layers) {
super(layers);
mAlpha = alpha;
}

@Override
public void draw(final Canvas canvas) {
final Rect bounds = getBounds();
canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, mAlpha);
super.draw(canvas);
canvas.restore();
}
}
}

+ 28
- 54
app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java 查看文件

@@ -22,6 +22,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Keep;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
@@ -50,11 +52,6 @@ public class FloatingActionsMenu extends ViewGroup {
private static final TimeInterpolator EXPAND_INTERPOLATOR = new OvershootInterpolator();
private static final TimeInterpolator COLLAPSE_INTERPOLATOR = new DecelerateInterpolator(3f);
private static final TimeInterpolator ALPHA_EXPAND_INTERPOLATOR = new DecelerateInterpolator();
private int mAddButtonPlusColor;
private int mAddButtonColorNormal;
private int mAddButtonColorPressed;
private int mAddButtonSize;
private boolean mAddButtonStrokeVisible;
private int mExpandDirection;
private int mButtonSpacing;
private int mLabelsMargin;
@@ -62,7 +59,7 @@ public class FloatingActionsMenu extends ViewGroup {
private boolean mExpanded;
private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
private AddFloatingActionButton mAddButton;
private FloatingActionButton mAddButton;
private RotatingDrawable mRotatingDrawable;
private int mMaxButtonWidth;
private int mMaxButtonHeight;
@@ -88,7 +85,7 @@ public class FloatingActionsMenu extends ViewGroup {
}

private void init(final Context context, final AttributeSet attributeSet) {
mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing) - getResources().getDimension(R.dimen.fab_shadow_radius) - getResources().getDimension(R.dimen.fab_shadow_offset));
mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing));
mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin);
mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);

@@ -96,14 +93,6 @@ public class FloatingActionsMenu extends ViewGroup {
setTouchDelegate(mTouchDelegateGroup);

final TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0);
mAddButtonPlusColor = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor,
FloatingActionButton.getColorFromTheme(context, android.R.attr.colorBackground, android.R.color.white));
mAddButtonColorNormal = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorNormal,
FloatingActionButton.getColorFromTheme(context, android.R.attr.colorAccent, android.R.color.holo_blue_bright));
mAddButtonColorPressed = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorPressed,
FloatingActionButton.darkenOrLightenColor(mAddButtonColorNormal)); //TODO(msf): use getColorForState on the accent color from theme instead to get darker states
mAddButtonSize = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonSize, FloatingActionButton.SIZE_NORMAL);
mAddButtonStrokeVisible = attr.getBoolean(R.styleable.FloatingActionsMenu_fab_addButtonStrokeVisible, true);
mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP);
mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0);
mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE);
@@ -125,45 +114,30 @@ public class FloatingActionsMenu extends ViewGroup {
}

private void createAddButton(final Context context) {
mAddButton = new AddFloatingActionButton(context) {
@Override
void updateBackground() {
mPlusColor = mAddButtonPlusColor;
mColorNormal = mAddButtonColorNormal;
mColorPressed = mAddButtonColorPressed;
mStrokeVisible = mAddButtonStrokeVisible;
super.updateBackground();
}

@Override
Drawable getIconDrawable() {
final RotatingDrawable rotatingDrawable = new RotatingDrawable(super.getIconDrawable());
mRotatingDrawable = rotatingDrawable;
final RotatingDrawable rotatingDrawable = new RotatingDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_action_add_inverse, context.getTheme()));
mRotatingDrawable = rotatingDrawable;

final TimeInterpolator interpolator = new OvershootInterpolator();
final TimeInterpolator interpolator = new OvershootInterpolator();

final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION);
final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION);
final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION);
final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION);

collapseAnimator.setInterpolator(interpolator);
expandAnimator.setInterpolator(interpolator);
collapseAnimator.setInterpolator(interpolator);
expandAnimator.setInterpolator(interpolator);

mExpandAnimation.play(expandAnimator);
mCollapseAnimation.play(collapseAnimator);

return rotatingDrawable;
}
};
mExpandAnimation.play(expandAnimator);
mCollapseAnimation.play(collapseAnimator);

mAddButton = new FloatingActionButton(context);
mAddButton.setImageDrawable(rotatingDrawable);
mAddButton.setId(R.id.fab_expand_menu_button);
mAddButton.setSize(mAddButtonSize);
mAddButton.setOnClickListener(v -> toggle());

addView(mAddButton, super.generateDefaultLayoutParams());
mButtonsCount++;
}

public void addButton(final FloatingActionButton button) {
public void addButton(final LabeledFloatingActionButton button) {
addView(button, mButtonsCount - 1);
mButtonsCount++;

@@ -172,7 +146,7 @@ public class FloatingActionsMenu extends ViewGroup {
}
}

public void removeButton(final FloatingActionButton button) {
public void removeButton(final LabeledFloatingActionButton button) {
removeView(button.getLabelView());
removeView(button);
button.setTag(R.id.fab_label, null);
@@ -257,9 +231,9 @@ public class FloatingActionsMenu extends ViewGroup {

final int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0;
// Ensure mAddButton is centered on the line where the buttons should be
final int buttonsHorizontalCenter = mLabelsPosition == LABELS_ON_LEFT_SIDE
final int buttonsHorizontalCenter = (mLabelsPosition == LABELS_ON_LEFT_SIDE
? r - l - mMaxButtonWidth / 2
: mMaxButtonWidth / 2;
: mMaxButtonWidth / 2);
final int addButtonLeft = buttonsHorizontalCenter - mAddButton.getMeasuredWidth() / 2;
mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight());

@@ -314,7 +288,7 @@ public class FloatingActionsMenu extends ViewGroup {
childY - mButtonSpacing / 2,
Math.max(childX + child.getMeasuredWidth(), labelRight),
childY + child.getMeasuredHeight() + mButtonSpacing / 2);
mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(touchArea, child));
mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(new Rect(touchArea), child));

label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);
label.setAlpha(mExpanded ? 1f : 0f);
@@ -407,17 +381,17 @@ public class FloatingActionsMenu extends ViewGroup {

for (int i = 0; i < mButtonsCount; i++) {
final FloatingActionButton button = (FloatingActionButton) getChildAt(i);
final String title = button.getTitle();

if (button == mAddButton || title == null ||
button.getTag(R.id.fab_label) != null) continue;
if (button instanceof LabeledFloatingActionButton) {
final String title = ((LabeledFloatingActionButton) button).getTitle();

final AppCompatTextView label = new AppCompatTextView(context);
label.setTextAppearance(context, mLabelsStyle);
label.setText(button.getTitle());
addView(label);
final AppCompatTextView label = new AppCompatTextView(context);
label.setTextAppearance(context, mLabelsStyle);
label.setText(title);
addView(label);

button.setTag(R.id.fab_label, label);
button.setTag(R.id.fab_label, label);
}
}
}



+ 55
- 0
app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java 查看文件

@@ -0,0 +1,55 @@
/*
* Copyright © 2014 Jerzy Chalupski
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package com.wireguard.android.widget.fab;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.widget.TextView;

import com.wireguard.android.R;

public class LabeledFloatingActionButton extends FloatingActionButton {

private final String title;

public LabeledFloatingActionButton(final Context context) {
this(context, null);
}

public LabeledFloatingActionButton(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}

public LabeledFloatingActionButton(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);

final TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.LabeledFloatingActionButton, 0, 0);
title = attr.getString(R.styleable.LabeledFloatingActionButton_fab_title);
attr.recycle();
}

TextView getLabelView() {
return (TextView) getTag(R.id.fab_label);
}

public String getTitle() {
return title;
}

@Override
public void setVisibility(final int visibility) {
final TextView label = getLabelView();
if (label != null) {
label.setVisibility(visibility);
}

super.setVisibility(visibility);
}

}

+ 3
- 2
app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java 查看文件

@@ -43,13 +43,14 @@ public class TouchDelegateGroup extends TouchDelegate {

@Override
public boolean onTouchEvent(@NonNull final MotionEvent event) {
if (!mEnabled) return false;
if (!mEnabled)
return false;

TouchDelegate delegate = null;

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
for (final TouchDelegate touchDelegate : mTouchDelegates) {
for (final TouchDelegate touchDelegate : mTouchDelegates) {
if (touchDelegate.onTouchEvent(event)) {
mCurrentTouchDelegate = touchDelegate;
return true;


二進制
查看文件


二進制
查看文件


二進制
查看文件


二進制
查看文件


二進制
查看文件


二進制
查看文件


二進制
查看文件


二進制
查看文件


二進制
查看文件


二進制
查看文件


+ 9
- 0
app/src/main/res/drawable/ic_action_add_inverse.xml 查看文件

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="?android:attr/colorBackground"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>

+ 11
- 10
app/src/main/res/layout/tunnel_list_fragment.xml 查看文件

@@ -23,7 +23,8 @@
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorBackground">
android:background="?android:attr/colorBackground"
android:clipChildren="false">

<android.support.v7.widget.RecyclerView
android:id="@+id/tunnel_list"
@@ -39,27 +40,27 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="8dp"
android:layout_margin="16dp"
app:fab_labelStyle="@style/fab_label"
app:fab_labelsPosition="left"
app:layout_dodgeInsetEdges="bottom">
android:clipChildren="false"
app:fab_labelsPosition="left" >

<com.wireguard.android.widget.fab.FloatingActionButton
<com.wireguard.android.widget.fab.LabeledFloatingActionButton
android:id="@+id/create_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{fragment::onRequestCreateConfig}"
app:fab_icon="@drawable/ic_action_edit_inverse"
app:fab_size="mini"
app:fabSize="mini"
app:srcCompat="@drawable/ic_action_edit_inverse"
app:fab_title="@string/create_empty" />

<com.wireguard.android.widget.fab.FloatingActionButton
<com.wireguard.android.widget.fab.LabeledFloatingActionButton
android:id="@+id/create_from_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{fragment::onRequestImportConfig}"
app:fab_icon="@drawable/ic_action_open_inverse"
app:fab_size="mini"
app:srcCompat="@drawable/ic_action_open_inverse"
app:fabSize="mini"
app:fab_title="@string/create_from_file" />
</com.wireguard.android.widget.fab.FloatingActionsMenu>
</android.support.design.widget.CoordinatorLayout>


+ 2
- 30
app/src/main/res/values/fab.xml 查看文件

@@ -3,46 +3,18 @@
<item name="fab_expand_menu_button" type="id"/>
<item name="fab_label" type="id"/>

<dimen name="fab_size_normal">56dp</dimen>
<dimen name="fab_size_mini">40dp</dimen>

<dimen name="fab_icon_size">24dp</dimen>

<dimen name="fab_plus_icon_size">14dp</dimen>
<dimen name="fab_plus_icon_stroke">2dp</dimen>

<dimen name="fab_shadow_offset">3dp</dimen>
<dimen name="fab_shadow_radius">9dp</dimen>

<dimen name="fab_stroke_width">1dp</dimen>

<dimen name="fab_actions_spacing">16dp</dimen>
<dimen name="fab_actions_spacing">24dp</dimen>
<dimen name="fab_labels_margin">8dp</dimen>

<declare-styleable name="FloatingActionButton">
<attr name="fab_colorPressed" format="color"/>
<attr name="fab_colorDisabled" format="color"/>
<attr name="fab_colorNormal" format="color"/>
<attr name="fab_icon" format="reference"/>
<attr name="fab_size" format="enum">
<enum name="normal" value="0"/>
<enum name="mini" value="1"/>
</attr>
<declare-styleable name="LabeledFloatingActionButton">
<attr name="fab_title" format="string"/>
<attr name="fab_stroke_visible" format="boolean"/>
</declare-styleable>
<declare-styleable name="AddFloatingActionButton">
<attr name="fab_plusIconColor" format="color"/>
</declare-styleable>
<declare-styleable name="FloatingActionsMenu">
<attr name="fab_addButtonColorPressed" format="color"/>
<attr name="fab_addButtonColorNormal" format="color"/>
<attr name="fab_addButtonSize" format="enum">
<enum name="normal" value="0"/>
<enum name="mini" value="1"/>
</attr>
<attr name="fab_addButtonPlusIconColor" format="color"/>
<attr name="fab_addButtonStrokeVisible" format="boolean"/>
<attr name="fab_labelStyle" format="reference"/>
<attr name="fab_labelsPosition" format="enum">
<enum name="left" value="0"/>


Loading…
取消
儲存