TextSwitcher
和ViewSwitcher
是什么,有什么用呢?
其实大家从名字就可以看出来其大概意思,TextSwitcher
是用来切换文本显示的,而ViewSwitcher
是用来切换视图显示的,实际上他们也的确是用来做这个的,只不过他们在切换视图显示的时候允许添加切换的动画效果。TextSwitcher
其实也是ViewSwitcher
的子类实现。
TextSwitcher使用
我们先来看看TextSwitcher
的用法:
关键布局代码如下:
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="change"/>
<TextSwitcher
android:id="@+id/switcher"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Java代码如下:
//设置显示Text文本的View创建工厂
//这是通过代码的方式创建显示文本的视图,也可以直接在布局中设置显示文本的视图,这个在讲ViewSwitcher的用法的时候再说
mTextSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
@Override
public View makeView() {
TextView t = new TextView(TextSwitcherActivity.this);
t.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
t.setTextAppearance(TextSwitcherActivity.this, android.R.style.TextAppearance_Large);
return t;
}
});
Animation in = AnimationUtils.loadAnimation(this,
android.R.anim.fade_in);
Animation out = AnimationUtils.loadAnimation(this,
android.R.anim.fade_out);
mTextSwitcher.setInAnimation(in);//设置文本出现动画
mTextSwitcher.setOutAnimation(out);//设置文本消失动画
mTextSwitcher.setCurrentText(String.valueOf(mCount));//设置初始值,初始值不显示动画
int mCount = 0;
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCount++;
mTextSwitcher.setText(String.valueOf(mCount));//更新文本显示值,会出现动画
}
});
当你点击界面上的按钮的时候,会不断的更新TextSwitcher
的显示值,而在更新过程中文本会出现一个淡入淡出的效果,这个效果就是通过动画产生的。
ViewSwitcher使用
接着我们再来看看ViewSwitcher
的使用
布局代码:
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="change"/>
<ViewSwitcher
android:id="@+id/viewSwitcher"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="300dp"
android:layout_height="300dp"
android:src="@drawable/image1"/>
<ImageView
android:layout_width="300dp"
android:layout_height="300dp"
android:src="@drawable/image2"/>
</ViewSwitcher>
上面的布局中我们给ViewSwitcher
添加了两个子视图,注意这里只能添加两个直接子视图,否则初始化会出现异常,至于原因后面接着说。前面说过TextSwitcher
也可以通过布局设置文本显示视图,它的设置方式与ViewSwitcher
其实也是一样的。
ok,接着上Java代码
//因为我们已经通过布局的方式设置了要切换的视图,所以就不需要再设置Factory去生成切换视图了
Animation slide_in_left = AnimationUtils.loadAnimation(this,
android.R.anim.slide_in_left);
Animation slide_out_right = AnimationUtils.loadAnimation(this,
android.R.anim.slide_out_right);
mViewSwitcher.setInAnimation(slide_in_left);//设置图片出现动画
mViewSwitcher.setOutAnimation(slide_out_right);//设置图片消失动画
mButton2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mViewSwitcher.showNext();
}
});
上面就是ViewSwitcher
的使用方式,其实用起来还是很简单的。通过自定义动画,我们可以为两个View切换时添加更多漂亮有趣的动画效果
使用场景
在Android开发中视图切换显示还是很常见的,比如应用加载数据时显示加载动画视图数据视图隐藏,而加载成功后加载动画视图隐藏数据视图显示,这个场景使用ViewSwitcher
来实现应该会更简单,更方便。
源码探究
- 前面说到过
ViewSwitcher
只能存在两个直接子视图,否则会初始化失败,这是为什么呢?通过源码我们可以找到答案
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (getChildCount() >= 2) {
throw new IllegalStateException("Can't add more than 2 views to a ViewSwitcher");
}
super.addView(child, index, params);
}
- 在前面
ViewSwitcher
的使用中我们点击按钮的时候直接调用了mViewSwitcher.showNext();
,既然只能有两个子视图,那我们每次点击都showNext()
怎么会没出现越界异常呢?ok,我们还是看看源码中是怎么实现的
@android.view.RemotableViewMethod
public void showNext() {
setDisplayedChild(mWhichChild + 1);
}
@android.view.RemotableViewMethod
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);
}
}
通过上面的实现我们可以看到当其显示的child索引出现越界之后,会自动的进行循环显示,这也是为什么一直调用showNext()
没出现越界异常的原因
切换原理
我们再来看看其切换显示过程中视图的显示和隐藏及动画是如何实现的
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);
}
}
}
上面的代码实现也很简单,当显示指定索引的child时,将其设置为可见并执行mInAnimation
,其他视图在设置为不可见并执行mOutAnimation
动画
Factory作用原理
public void setFactory(ViewFactory factory) {
mFactory = factory;
obtainView();
obtainView();
}
private View obtainView() {
View child = mFactory.makeView();
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp == null) {
lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
addView(child, lp);
return child;
}
通过源码实现我们可以知道mTextSwitcher.setFactory(mFactory)
设置完成之后,ViewSwitcher
会立刻生成两个视图作为其子视图作为切换显示用。