網站首頁 編程語言 正文
一、ViewFlipper
在很多APP都有如下的公告通知效果(上下自動翻滾)
這種效果可以使用很多方式實現,有一個簡便的方式可以使用ViewFlipper控件實現,ViewFlipper控件繼承結果如下:
可以看出ViewFlipper繼承自ViewAnimator,ViewAnimator可以將在添加到其中的兩個或多個子View之間進行動畫處理的簡單。一次只顯示子View。可以定期在每個子View之間自動翻轉。
現在使用ViewFlipper自動上下滾動效果,非常簡單,布局文件中定義ViewFlipper
... <ViewFlipper android:id="@+id/vf_test" android:layout_width="match_parent" android:layout_height="50dip" android:autoStart="true" android:background="#00dd00" android:inAnimation="@anim/anim_in" android:outAnimation="@anim/anim_out"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:paddingLeft="10dip" android:text="這第1條消息." android:textSize="20sp" android:textStyle="bold" /> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:paddingLeft="10dip" android:text="這第2條消息.." android:textSize="20sp" android:textStyle="bold" /> </ViewFlipper> ...
顯示效果如下:
默認ViewFlipper是無動畫,這里通過inAnimation、outAnimation配置來子View進入和移出動畫,
inAnimation動畫配置如下文件(anim/anim_in.xml):
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:fromYDelta="100%p" android:toYDelta="0" /> <alpha android:duration="500" android:fromAlpha="0.0" android:toAlpha="1.0" /> </set>
outAnimation動畫配置如下文件(anim/anim_out.xml):
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:fromYDelta="0" android:toYDelta="-100%p" /> <alpha android:duration="500" android:fromAlpha="1.0" android:toAlpha="0.0" /> </set>
可以看出,這里的兩個動畫文件均使用的是補間動畫的動畫集合(位移動畫、透明度動畫)
ViewFlipper可配置的參數:
android:autoStart : 設置顯示該組件是否是自動播放(默認 false)
android:inAnimation : 設置組件進入時使用的動畫
android:outAnimation : 設置組件移出時使用的動畫
android:flipInterval:設置自動播放的時間間隔(ViewFlipper默認3000ms)
android:animateFirstView:設置顯示該組件的第一個View時是否使用動畫(默認true,可以手動向空的ViewFlipper addView 方式添加View看到效果)
ViewFlipper可以通過代碼設置上述配置(不再列舉),也可以通過代碼來控制播放,具體api如下:
startFlipping() :開始播放
stopFlipping() : 停止播放
通常情況下我們滾動的內容是服務器下發的,所以個數無法得知,如果個數少的情況,使用ViewFlipper展示此效果沒有什么大的問題,一但出現多數據情況,可能會出現內存上升。
例如:有10000條數據情況:
定義一個空的ViewFlipper,如下:
... <ViewFlipper android:id="@+id/vf_test" android:layout_width="match_parent" android:layout_height="50dip" android:autoStart="true" android:background="#00dd00" android:inAnimation="@anim/anim_in" android:outAnimation="@anim/anim_out"> </ViewFlipper> ...
每個子View布局(item_view.xml)如下:
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:paddingLeft="10dip" android:textSize="20sp" android:textStyle="bold" />
再通過代碼方式添加子View,如下:
...
ViewFlipper vf_test = (ViewFlipper) findViewById(R.id.vf_test);
for (int i = 0; i < 10000; i++) {
TextView textView = (TextView) LayoutInflater.from(DemoActivity.this).inflate(R.layout.item_view, null);
textView.setText("這是第" + i + "條消息");
vf_test.addView(textView);
}
...
運行APP可以明顯看出頁面卡頓來幾秒后才顯示,內存使用情況如下:
這里的每個item還僅為一個TextView,如果每個item布局復雜,所占用的內存更高。像這種大數據的情況,我們可以使用適配器模式的ViewFlipper(AdapterViewFlipper)來替代。
二、AdapterViewFlipper
AdapterViewFlipper的繼承關系如下:
注:AdapterViewFlipper是api11(Android 3.0)中新增的,現在的APP最低支持版本肯定大于此版本,基本可以忽略。
從繼承關系可以看出AdapterViewFlipper同ListView類似,都繼承了AdapterView,所以AdapterViewFlipper可以像ListView一樣使用數據適配器來填充數據。
先定義一個AdapterViewFlipper如下:
... <AdapterViewFlipper android:id="@+id/avf_view" android:layout_width="match_parent" android:layout_height="50dip" android:autoStart="true" android:background="#00FF00" android:flipInterval="3000" android:inAnimation="@animator/anim_in" android:outAnimation="@animator/anim_out" /> ...
同ViewFlipper,AdapterViewFlipper默認是無動畫,這里通過inAnimation、outAnimation配置來子View進入和移出動畫(注意這里只能配置單一的ObjectAnimator屬性動畫),這里設置了一個自動播放動畫間隔(android:flipInterval)3000毫秒,因為AdapterViewFlipper默認間隔是10000毫秒,android:autoStart 同ViewFlipper設置動畫是否自動播放,android:animateFirstView在AdapterViewFlipper設置是無效的。
這里AdapterViewFlipper因為繼承自AdapterViewAnimator所以它也有android:loopViews(設置循環到最后一個組件后是否自動“轉頭”到第一個組件)配置,但是,AdapterViewFlipper設置這個屬性無效,源碼解釋為視圖翻轉器應該循環瀏覽視圖(在AdapterViewFlipper構造函數中將loopViews設置了true)
AdapterViewFlipper同ViewFlipper可以通過代碼設置上述配置(不再列舉),也可以通過代碼來控制播放,具體api如下:
startFlipping() :開始播放
stopFlipping() : 停止播放
inAnimation動畫配置如下文件(animator/anim_in.xml):
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:propertyName="translationY" android:valueFrom="150" android:valueTo="0" />
這里屬性動畫存放在animator目錄下。
outAnimation動畫配置如下文件(animator/anim_out.xml):
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:propertyName="translationY" android:valueFrom="0" android:valueTo="-150"/>
這里的valueFrom、valueTo是移動距離(像素),如想適配,可使用代碼創建屬性動畫計算View移動的精確距離。
AdapterViewFlipper因為繼承了AdapterView,所以需要通過代碼設置一個Adapter展現效果,數據適配器如下:
public class ViewFlipperAdapter extends BaseAdapter {
private Context context;
private List<String> data;
public ViewFlipperAdapter(Context context, List<String> data) {
this.context = context;
this.data = data;
}
@Override
public int getCount() {
return data == null ? 0 : data.size();
}
@Override
public Object getItem(int position) {
return data == null ? null : data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(context).inflate(R.layout.item_view, parent,false);
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tv_item.setText(data.get(position));
return view;
}
static class ViewHolder {
public TextView tv_item;
public ViewHolder(View view) {
this.tv_item = view.findViewById(R.id.tv_item);
}
}
}
這里使用ViewHolder做了數據適配器View緩存處理,效率更高。
這里的每個item布局(item_view)如下:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv_item" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:textSize="20sp" android:textStyle="bold" />
最后設置數據適配器到AdapterViewFlipper上即可:
...
AdapterViewFlipper avf_view = (AdapterViewFlipper) findViewById(R.id.avf_view);
List<String> data = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
data.add("這是第" + i + "條消息");
}
ViewFlipperAdapter viewFlipperAdapter = new ViewFlipperAdapter(this, data);
//也可通過代碼設置動畫
//avf_view.setInAnimation(ObjectAnimator.ofFloat(avf_view, View.TRANSLATION_Y,150.0f,0.0f));
//avf_view.setOutAnimation(ObjectAnimator.ofFloat(avf_view, View.TRANSLATION_Y,0.0f,-150.0f));
avf_view.setAdapter(viewFlipperAdapter);
...
這里直接構造了10000條數據,因為有了數據適配器,運行很輕松。
顯示效果與ViewFlipper例子中基本一致,因為AdapterViewFlipper只能設置單一屬性動畫,所以此處沒有漸變動畫,只有位移動畫。
內存使用情況如下:
AdapterViewFlipper繼承了AdapterView,所以同ListView,也可以設置setOnItemClickListener來監聽每個Item的點擊事件,當然也可以在數據適配中為每一個Item設置點擊事件。這里如果setOnItemClickListener設置每個Item的點擊事件,默認是不回調的,因為AdapterViewFlipper父類AdapterViewAnimator中重寫了onTouchEvent函數,但是在MotionEvent.ACTION_DOWN時返回值一直是false,導致onTouchEvent函數中的MotionEvent.ACTION_UP,無法回調,從而無法回調OnItemClickListener,因此要想使回調生效,只需重寫onTouchEvent函數,并返回true即可:
public class MyAdapterViewFlipper extends AdapterViewFlipper {
public MyAdapterViewFlipper(Context context) {
super(context);
}
public MyAdapterViewFlipper(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyAdapterViewFlipper(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyAdapterViewFlipper(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
return true;
}
}
代碼中可以使用MyAdapterViewFlipper,這樣設置setOnItemClickListener就可以正常回調了。
Android ViewFlipper、AdapterViewFlipper對比
復用性
ViewFlipper中的子view只能在xml中提前寫好,或者在代碼中通過 addView 的形式添加,這種形式不具有復用性質,只能處理較少的數據。
AdapterViewFlipper 因為有數據適配器,所以具有復用屬性,可以處理大量的數據。
動畫效果
ViewFlipper在設置動畫時接收的是Animation——補間動畫,可以是單一動畫效果,也可以是動畫集合。
AdapterViewFlipper 在設置動畫的時候接收的是 ObjectAnimator——屬性動畫,而且只能是單一動畫,不能使用動畫集合。
屬性配置
ViewFlipper的默認Interval為3000ms(3秒);
AdapterViewFlipper的默認Interval為10000ms(10秒);
ViewFlipper只有1條數據也執行動畫,AdapterViewFlipper只有1條數據時不會執行動畫;
AdapterViewFlipper比ViewFlipper多一個android:loopViews配置,但是AdapterViewFlipper設置此屬性無效;
AdapterViewFlipper中設置android:animateFirstView是無效的,在ViewFlipper中設置有效;
總結
原文鏈接:https://juejin.cn/post/7095982852763811876
相關推薦
- 2023-01-30 vite?+?react?+typescript?環境搭建小白入門教程_React
- 2022-03-03 設置setInterval定時器、postMessage、addEventListener監聽器
- 2023-07-09 css樣式重疊解決辦法
- 2023-01-01 MongoDB?Shell常用基本操作命令詳解_MongoDB
- 2022-04-06 Android關于Button背景或樣式失效問題解決方法_Android
- 2023-07-09 關于 axios 是什么?以及怎么用?
- 2023-07-25 mybatis-plus在實際開發中的應用
- 2022-09-14 Android?Activity通用懸浮可拖拽View封裝的思路詳解_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支