Android自定义View--使用ViewAnimator实现一个提交按钮

效果图

这里写图片描述

准备知识

SendCommentButton

新建SendCommentButton继承自ViewAnimator,而ViewAnimator是继承自FrameLayout的。

public class SendCommentButton extends ViewAnimator{

        //通过代码new执行该方法
    public SendCommentButton(Context context) {
        super(context);
        init();
    }


    //通过xml引入会执行该方法
    public SendCommentButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
}

init()方法

 private void init() {
        LayoutInflater.from(getContext()).inflate(R.layout.view_send_comment_button, this, true);
    }

把布局依附到该控件上
R.layout.view_send_comment_button布局

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:id="@+id/tvSend"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="SEND"
        android:textColor="#ffffff"
        android:textSize="12sp" />

    <TextView
        android:id="@+id/tvDone"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="✓"
        android:textColor="#ffffff"
        android:textSize="12sp" />
</merge>

执行init()方法之后会回调ViewAnimatoraddView方法,我们来看看ViewAnimator是怎么处理的

    ......

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        if (getChildCount() == 1) {
            child.setVisibility(View.VISIBLE);
        } else {
            child.setVisibility(View.GONE);
        }
        if (index >= 0 && mWhichChild >= index) {
            // Added item above current one, increment the index of the displayed child
            setDisplayedChild(mWhichChild + 1);
        }
    }
    ......

从上面可以看到把第一个子View设置为可见,其他设置GONE,也就是说merge设置为GONE了。
接下来我们补充SendCommentButton其他逻辑代码

public class SendCommentButton extends ViewAnimator implements View.OnClickListener {
    public static final int STATE_SEND = 0;
    public static final int STATE_DONE = 1;
    private static final long RESET_STATE_DELAY_MILLIS = 2000;

    private int currentState;
    private OnSendClickListener onSendClickListener;


    //通过代码new执行该方法
    public SendCommentButton(Context context) {
        super(context);
        init();
    }


    //通过xml引入会执行该方法
    public SendCommentButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        LayoutInflater.from(getContext()).inflate(R.layout.view_send_comment_button, this, true);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        currentState = STATE_SEND;
        setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (onSendClickListener != null) {
            onSendClickListener.onSendClickListener(this);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        removeCallbacks(revertStateRunnable);
        super.onDetachedFromWindow();
    }

    public void setCurrentState(int state) {
        if (state == currentState) {
            return;
        }
        currentState = state;
        if (state == STATE_DONE) {
            setEnabled(false);
            postDelayed(revertStateRunnable, RESET_STATE_DELAY_MILLIS);
            setInAnimation(getContext(), R.anim.slide_in_done);
            setOutAnimation(getContext(), R.anim.slide_out_send);
        } else if (state == STATE_SEND) {
            setEnabled(true);
            setInAnimation(getContext(), R.anim.slide_in_send);
            setOutAnimation(getContext(), R.anim.slide_out_done);
        }
        showNext();
    }

    private Runnable revertStateRunnable = new Runnable() {
        @Override
        public void run() {
            setCurrentState(STATE_SEND);
        }
    };

    public interface OnSendClickListener {
        void onSendClickListener(View v);
    }

    public void setOnSendClickListener(OnSendClickListener onSendClickListener) {
        this.onSendClickListener = onSendClickListener;
    }



}

上面定义了两种状态,暴露了一个接口和设置了进入和进出动画。这里解析一下ViewAnimatorshowNext()方法,在ViewAnimator的源码中

    ......
 public void showNext() {
        setDisplayedChild(mWhichChild + 1);
    }
    ......

showNext会调用setDisplayedChild方法

 /**
     * Sets which child view will be displayed.
     *设置哪个子View将被显示
     * @param whichChild the index of the child view to display 要显示子view的下标
     */
 public void setDisplayedChild(int whichChild) {
        mWhichChild = whichChild;
        if (whichChild >= getChildCount()) {
            mWhichChild = 0;
        } else if (whichChild < 0) {
            mWhichChild = getChildCount() - 1;
        }
        boolean hasFocus = getFocusedChild() != null;
        // This will clear old focus if we had it
        showOnly(mWhichChild);
        if (hasFocus) {
            // Try to retake focus if we had it
            requestFocus(FOCUS_FORWARD);
        }
    }

setDisplayedChild中的主要展示逻辑交给了showOnly方法

 /**
     * Shows only the specified child. The other displays Views exit the screen,
     * optionally with the with the {@link #getOutAnimation() out animation} and
     * the specified child enters the screen, optionally with the
     * {@link #getInAnimation() in animation}.
     *
     * @param childIndex The index of the child to be shown.
     * @param animate Whether or not to use the in and out animations, defaults
     *            to true.
     */
    void showOnly(int childIndex, boolean animate) {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (i == childIndex) {
                if (animate && mInAnimation != null) {
                    child.startAnimation(mInAnimation);
                }
                child.setVisibility(View.VISIBLE);
                mFirstTime = false;
            } else {
                if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
                    child.startAnimation(mOutAnimation);
                } else if (child.getAnimation() == mInAnimation)
                    child.clearAnimation();
                child.setVisibility(View.GONE);
            }
        }
    }

    /**
     * Shows only the specified child. The other displays Views exit the screen
     * with the {@link #getOutAnimation() out animation} and the specified child
     * enters the screen with the {@link #getInAnimation() in animation}.
         *正在展示的view退出屏幕,展示指定的view,指定的view以getInAnimation的动画进入,退出的view以getOutAnimation的动画退出
     * @param childIndex The index of the child to be shown.
     */
    void showOnly(int childIndex) {
        final boolean animate = (!mFirstTime || mAnimateFirstTime);
        showOnly(childIndex, animate);
    }

重点看下这段代码

  for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (i == childIndex) {
                if (animate && mInAnimation != null) {
                    child.startAnimation(mInAnimation);
                }
                child.setVisibility(View.VISIBLE);
                mFirstTime = false;
            } else {
                if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
                    child.startAnimation(mOutAnimation);
                } else if (child.getAnimation() == mInAnimation)
                    child.clearAnimation();
                child.setVisibility(View.GONE);
            }
        }

从上面可以看到ViewAnimator把我们之前设置的setInAnimation(getContext(), R.anim.slide_in_done);
setOutAnimation(getContext(), R.anim.slide_out_send);
应用到进入和退出View上。

下载地址

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中的自定义 View 是开发中非常重要的一部分,可以帮助开发者创建出各种各样的交互效果和用户界面。本文将介绍如何使用 Android Studio 实现一个简单的自定义 View。 1. 创建一个新项目并新建一个自定义 View 类 在 Android Studio 中创建一个新的项目,并在其中创建一个新的类,命名为 CustomView。CustomView 继承自 View,因此需要在该类中添加构造函数和必要的方法。 ```java public class CustomView extends View { public CustomView(Context context) { super(context); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制代码 } } ``` 2. 在 CustomView 中添加绘制代码 在 CustomView 的 onDraw 方法中添加绘制代码,绘制一个简单的圆形,在这里我们使用 Canvas 和 Paint 类来绘制图形。 ```java @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, paint); } ``` 3. 在布局文件中添加 CustomView 在布局文件中添加 CustomView,设置宽度和高度为 200dp,并设置背景色为白色。 ```xml <com.example.customview.CustomView android:layout_width="200dp" android:layout_height="200dp" android:background="@android:color/white" /> ``` 4. 运行程序 完成以上步骤后,即可运行程序,在屏幕上看到一个红色的圆形。 完整代码如下: ```java public class CustomView extends View { public CustomView(Context context) { super(context); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, paint); } } ``` ```xml <com.example.customview.CustomView android:layout_width="200dp" android:layout_height="200dp" android:background="@android:color/white" /> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值