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上。
下载地址
参考
相关文章推荐
- 4000 Android自定义View--使用NestScrolling机制实现一个上下滑动退出Layout
- 自定义View实战--实现一个清新美观的加载按钮
- Android客户端之“微服私访”App的系统学习(七)XRecyclerView快速实现列表界面+自定义Search输入框,软键盘搜索按钮监听+TextView部分样式改变
- Android自定义View之实现一个动态的文字闪动效果
- Android中使用自定义selector来实现view的点击效果以及view的显示样式
- Android使用自定义View继承SurfaceView实现动态折线图的绘制
- android开发之&使用ViewPager加gridView实现菜单按钮分页滑动(类似QQ表情选择翻页效果)
- android自定义view实现一个钟表
- Android 自定义dialog,实现右上角显示一个控件按钮
- 【新建项目&使用viewPager】实现一个Android电子书阅读APP
- Android自定义View实现开关按钮
- Android使用RecyclerView实现自定义列表、点击事件以及下拉刷新
- Android自定义一个View实现运动的小人
- 【新建项目&使用viewPager】实现一个Android电子书阅读APP
- Android中使用SurfaceView+MediaPlayer+自定义的MediaController实现自定义的视屏播放器
- Android 自定义 HorizontalScrollView 实现图片左右滚动按钮控制
- Android中使用自定义View实现下载进度的显示
- Android 使用自定义ViewGroup实现圆形布局
- 【新建项目&使用viewPager】实现一个Android电子书阅读APP
- Android圆形图片不求人,自定义View实现(BitmapShader使用)