您的位置:首页 > 移动开发 > Android开发

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

2017-07-09 12:14 1151 查看

效果图



准备知识

merge
标签的使用,可以参考Android 布局优化之include与merge

ViewAnimator

Android
自定义组件

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="SEN
4000
D"
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()
方法之后会回调
ViewAnimator
addView
方法,我们来看看
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;
}

}


上面定义了两种状态,暴露了一个接口和设置了进入和进出动画。这里解析一下
ViewAnimator
showNext()
方法,在
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
上。

下载地址

参考

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐