我想创建一个自定义的FAB,其工作方式如下图所示
但是我能做的就是这样
我在这里所做的是创建一个包含自定义视图的XML布局。
并创建了一个扩展了Constraint layout
的视图并创建了自定义背景,并添加了ValueAnimator
来更改视图的高度
这是我的代码:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parent_fab"
android:layout_width="60dp"
android:layout_height="60dp"
android:animateLayoutChanges="true"
android:background="@drawable/fab"
android:clipChildren="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/firstIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="20dp"
android:src="@drawable/ic_account_balance_black_24dp"
android:tooltipText="Remise Par Scanbox"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/secondIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="20dp"
android:src="@drawable/ic_photo_camera_black_24dp"
android:tooltipText="Remise Par Courrier"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/mainIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="20dp"
android:src="@drawable/ic_add_black_24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
</android.support.constraint.ConstraintLayout>
java代码:
public class ExpandableFabView extends ConstraintLayout {
private ConstraintLayout fab;
private ImageView mainIcon;
private ImageView firstIcon;
private ImageView seconIcon;
private int width;
private int height;
private Context context;
private LayerDrawable ld;
private ShapeDrawable fabDrawable;
private boolean expanded = false;
private long mLastClickTime = 0;
public ExpandableFabView(@NonNull Context context) {
super(context);
this.context = context;
init();
}
public ExpandableFabView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public ExpandableFabView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init();
}
void init() {
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mInflater.inflate(R.layout.expandablefab, this, true);
fab = findViewById(R.id.parent_fab);
mainIcon = findViewById(R.id.mainIcon);
firstIcon = findViewById(R.id.firstIcon);
seconIcon = findViewById(R.id.secondIcon);
mainIcon.setOnClickListener(v -> {
if (SystemClock.elapsedRealtime() - mLastClickTime < 500) {
return;
}
mLastClickTime = SystemClock.elapsedRealtime();
slideView(fab.getHeight(), expanded ? fab.getHeight() / 3 : fab.getHeight() * 3, expanded);
expanded = !expanded;
});
setViewBackground();
dropShadow();
}
public void slideView(int currentHeight, int newHeight, boolean reversed) {
fab.setPivotY(0f);
ValueAnimator scaleAnimator = ValueAnimator
.ofInt(currentHeight, newHeight)
.setDuration(500);
ValueAnimator slideAnimator = ValueAnimator
.ofFloat(fab.getY(), fab.getBottom())
.setDuration(500);
/* We use an update listener which listens to each tick
* and manually updates the height of the view */
scaleAnimator.addUpdateListener(animation1 -> {
fab.getLayoutParams().height = (int) (Integer) animation1.getAnimatedValue();
fab.requestLayout();
fab.postInvalidate();
requestLayout();
invalidate();
});
/*slideAnimator.addUpdateListener(animation1 -> {
fab.animate().translationY(-(Float) animation1.getAnimatedValue());
fab.requestLayout();
fab.postInvalidate();
});
*/
/* We use an animationSet to play the animation */
AnimatorSet animationSet = new AnimatorSet();
animationSet.setInterpolator(new AccelerateDecelerateInterpolator());
animationSet.play(scaleAnimator).with(slideAnimator);
animationSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
mainIcon.animate().rotation(reversed ? 0 : 315);
firstIcon.animate().alpha(reversed ? 0 : 1).rotation(reversed ? -360 : 0).setStartDelay(100);
seconIcon.animate().alpha(reversed ? 0 : 1).rotation(reversed ? 360 : 0).setStartDelay(200);
}
});
animationSet.start();
}
void dropShadow() {
RoundRectShape roundRectShape = new RoundRectShape(new float[]{100f, 100f, 100f,
100f, 100f, 100f, 100f, 100f}, null, null);
ShapeDrawable shapeDrawable = new ShapeDrawable(roundRectShape);
shapeDrawable.setShaderFactory(new ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new LinearGradient(0, 0, 0, height,
new int[]{Color.MAGENTA, Color.BLUE},
new float[]{0, 1f},
Shader.TileMode.REPEAT);
}
});
ld = new LayerDrawable(new Drawable[]{fabDrawable, shapeDrawable});
ld.setLayerInset(0, 5, 5, 0, 0); // inset the shadow so it doesn't start right at the left/top
ld.setLayerInset(1, 0, 0, 5, 5);
fab.setBackground(ld);
}
void setViewBackground() {
RoundRectShape roundRectShape = new RoundRectShape(new float[]{100f, 100f, 100f,
100f, 100f, 100f, 100f, 100f}, null, null);
fabDrawable = new ShapeDrawable(roundRectShape);
fabDrawable.setShaderFactory(new ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new LinearGradient(0, 0, 0, height,
new int[]{Color.parseColor("#e5e5e5"), Color.parseColor("#e5e5e5")},
new float[]{0, 1},
Shader.TileMode.REPEAT);
}
});
fab.setBackground(fabDrawable);
}
答案 0 :(得分:0)
您应该像这样更改PivotPoint,
parentFab.setPivotY(0f);
这会将固定点(当前在y轴和x轴上居中)设置为顶部,因此动画将向下展开。如果需要,可以简单地设置为0f
的parentFab高度。