Android自定義ViewFlipper實(shí)現(xiàn)滾動(dòng)效果
本文實(shí)例為大家分享了自定義view實(shí)現(xiàn)了類似百度手機(jī)助手,首頁(yè)評(píng)論滾動(dòng)效果。
看效果:

gif做的不好,其效果就是:幾個(gè)viewitem不停的向上滾動(dòng),新加入item有個(gè)淡入的效果。
說(shuō)下實(shí)現(xiàn)思路:自定義view繼承至LinearLayout,控制item數(shù)量及其動(dòng)畫效果,實(shí)現(xiàn)item復(fù)用,傳入數(shù)據(jù)即可,使用方便。
代碼:
/**
* Jiantao.Yang
*
* @description 仿百度手機(jī)助手,評(píng)論滾動(dòng)效果
* @time 2015/1/16 17:37
*/
public class ViewFlipper extends LinearLayout {
private final int MAX_SHOW_ITEM_SIZE = 5;
private IAdapter mIAdapter;
private int mCount;
//最后一個(gè)item動(dòng)畫
private Animation mLastOneAnimation;
//其它item動(dòng)畫
private Animation mCommonAnimation;
//數(shù)據(jù)下標(biāo)
private int mCurrentIndex;
/**
* 這里動(dòng)畫時(shí)間是1600毫秒,所以間隔得大于動(dòng)畫時(shí)間
*/
private static final int DEFAULT_INTERVAL = 2000;
private int mFlipInterval = DEFAULT_INTERVAL;
private boolean mAutoStart = false;
private boolean mRunning = false;
private boolean mStarted = false;
private boolean mVisible = false;
private boolean mUserPresent = true;
public ViewFlipper(Context context) {
super(context);
init(context);
}
public ViewFlipper(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ViewFlipper(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
mUserPresent = false;
updateRunning();
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
mUserPresent = true;
updateRunning(false);
}
}
};
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// Listen for broadcasts related to user-presence
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
// OK, this is gross but needed. This class is supported by the
// remote views machanism and as a part of that the remote views
// can be inflated by a context for another user without the app
// having interact users permission - just for loading resources.
// For exmaple, when adding widgets from a user profile to the
// home screen. Therefore, we register the receiver as the current
// user not the one the context is for.
getContext().registerReceiver(mReceiver, filter);
if (mAutoStart) {
// Automatically start when requested
startFlipping();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mVisible = false;
getContext().unregisterReceiver(mReceiver);
updateRunning();
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mVisible = visibility == VISIBLE;
updateRunning(mVisible);
// updateRunning(false);
}
private void init(Context context) {
this.setOrientation(LinearLayout.VERTICAL);
}
public void setIAdapter(IAdapter iAdapter) {
this.mIAdapter = iAdapter;
initShowItems();
}
public void startFlipping() {
mStarted = true;
updateRunning();
}
public void stopFlipping() {
mStarted = false;
updateRunning();
}
private void updateRunning() {
updateRunning(true);
}
/**
* Returns true if the child views are flipping.
*/
public boolean isFlipping() {
return mStarted;
}
/**
* Set if this view automatically calls {@link #startFlipping()} when it
* becomes attached to a window.
*/
public void setAutoStart(boolean autoStart) {
mAutoStart = autoStart;
}
/**
* Returns true if this view automatically calls {@link #startFlipping()}
* when it becomes attached to a window.
*/
public boolean isAutoStart() {
return mAutoStart;
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(ViewFlipper.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(ViewFlipper.class.getName());
}
/**
* 初始化childViews
*/
private void initShowItems() {
if (mIAdapter != null) {
mCount = mIAdapter.getCount();
for (int i = 0; i < mCount; i++) {
if (i == MAX_SHOW_ITEM_SIZE) {
break;
}
View convertView = getChildAt(i);
View item = mIAdapter.getItemView(convertView, i);
addView(item, i);
}
}
}
/**
* Internal method to start or stop dispatching flip {@link android.os.Message} based
* on {@link #mRunning} and {@link #mVisible} state.
*
* @param flipNow Determines whether or not to execute the animation now, in
* addition to queuing future flips. If omitted, defaults to
* true.
*/
private void updateRunning(boolean flipNow) {
boolean running = mVisible && mStarted && mUserPresent;
System.out.println(" updateRunning running:" + running + " mVisible " + mVisible + " userPresent " + mUserPresent);
if (running != mRunning) {
if (running && (mCount > MAX_SHOW_ITEM_SIZE)) {
showItems(mCurrentIndex++, flipNow);
Message msg = mHandler.obtainMessage(FLIP_MSG);
mHandler.sendMessageDelayed(msg, mFlipInterval);
} else {
mHandler.removeMessages(FLIP_MSG);
}
mRunning = running;
}
}
private void showItems(final int position, boolean animate) {
if (animate && (mLastOneAnimation == null || mCommonAnimation == null)) {
mLastOneAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.lastone_anim);
mCommonAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.common_anim);
}
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
child.clearAnimation();
int index = position + i;
child = mIAdapter.getItemView(child, (index >= mIAdapter.getCount()) ? (index - mIAdapter.getCount()) : index);
if (animate) {
if (i == childCount - 1) {
child.setAnimation(mLastOneAnimation);
} else {
child.setAnimation(mCommonAnimation);
}
}
child.setVisibility(View.VISIBLE);
}
if (animate) {
mCommonAnimation.startNow();
mLastOneAnimation.startNow();
}
//保證傳入的position小于getCount
if (mCurrentIndex >= mIAdapter.getCount()) {
mCurrentIndex = 0;
}
}
private final int FLIP_MSG = 1;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == FLIP_MSG) {
if (mRunning) {
showItems(mCurrentIndex++, true);
msg = obtainMessage(FLIP_MSG);
sendMessageDelayed(msg, mFlipInterval);
}
}
}
};
public interface IAdapter {
/**
* @param convertView
* @param position
* @return
*/
public View getItemView(View convertView, int position);
/**
* @return 數(shù)據(jù)count
*/
public int getCount();
}
}
再來(lái)看看調(diào)用部分:
public class MainActivity extends ActionBarActivity implements ViewFlipper.IAdapter {
ViewFlipper viewFlipper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewFlipper = (ViewFlipper) findViewById(R.id.view_flipper);
viewFlipper.setIAdapter(this);
}
@Override
protected void onResume() {
super.onResume();
viewFlipper.startFlipping();
}
@Override
public View getItemView(View convertView, int position) {
View item = null;
TextView textView;
if (convertView == null) {
item = View.inflate(this, R.layout.item, null);
} else {
item = convertView;
}
textView = (TextView) item.findViewById(R.id.textview);
textView.setText("測(cè)試數(shù)據(jù):" + position);
return item;
}
@Override
public int getCount() {
return 8;
}
}
可以看出,MainActivity實(shí)現(xiàn)了ViewFlipper.IAdapter接口,setAdapter后調(diào)用startFlipper即可。
這里布局文件我就不貼出來(lái)了,附上工程源碼,項(xiàng)目里動(dòng)畫時(shí)間有點(diǎn)長(zhǎng),修改下就ok。
限于水平有限,不足之處難免,望各位不舍指正,與君共勉。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android使用ViewFlipper實(shí)現(xiàn)上下滾動(dòng)消息
- Android仿淘寶頭條向上滾動(dòng)廣告條ViewFlipper
- Android控件ViewFlipper仿淘寶頭條垂直滾動(dòng)廣告條
- android開發(fā)之橫向滾動(dòng)/豎向滾動(dòng)的ListView(固定列頭)
- android實(shí)現(xiàn)上下滾動(dòng)的TextView
- android TextView不用ScrollViewe也可以滾動(dòng)的方法
- android 實(shí)現(xiàn)ScrollView自動(dòng)滾動(dòng)的實(shí)例代碼
- Android中實(shí)現(xiàn)多行、水平滾動(dòng)的分頁(yè)的Gridview實(shí)例源碼
- Android GridView實(shí)現(xiàn)滾動(dòng)到指定位置的方法
- android開發(fā)教程之文本框加滾動(dòng)條scrollview
相關(guān)文章
Android設(shè)置透明狀態(tài)欄和透明導(dǎo)航欄
本文主要介紹了Android設(shè)置透明狀態(tài)欄和透明導(dǎo)航欄的方法。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03
Android中使用OkHttp包處理HTTP的get和post請(qǐng)求的方法
OkHttp包為安卓開發(fā)中的HTTP協(xié)議網(wǎng)絡(luò)編程帶來(lái)了很大的便利,這里我們就來(lái)看一下最基本的、Android中使用OkHttp包處理HTTP的get和post請(qǐng)求的方法:2016-07-07
Android利用GridView實(shí)現(xiàn)單選效果
本篇文章主要介紹了Android利用GridView實(shí)現(xiàn)單選效果的相關(guān)知識(shí),具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-05-05
Android實(shí)現(xiàn)的仿淘寶購(gòu)物車demo示例
這篇文章主要介紹了Android實(shí)現(xiàn)的仿淘寶購(gòu)物車demo示例,結(jié)合實(shí)例形式分析了Android購(gòu)物車的功能、布局及邏輯實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-07-07
Android編程實(shí)現(xiàn)通訊錄中聯(lián)系人的讀取,查詢,添加功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)通訊錄中聯(lián)系人的讀取,查詢,添加功能,涉及Android權(quán)限控制及通訊錄相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
Android超實(shí)用的Toast提示框優(yōu)化分享
Toast是Android中用來(lái)顯示顯示信息的一種機(jī)制,和Dialog不一樣的是,Toast是沒有焦點(diǎn)的,而且Toast顯示的時(shí)間有限,過(guò)一定的時(shí)間就會(huì)自動(dòng)消失。那么這篇文章跟大家分享下Android中Toast的優(yōu)化,對(duì)大家日常開發(fā)還是很實(shí)用,下面來(lái)一起看看吧。2016-09-09

