服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android自定义ViewFlipper实现滚动效果

Android自定义ViewFlipper实现滚动效果

2022-10-28 13:46jiantaocd Android

这篇文章主要为大家详细介绍了Android自定义ViewFlipper实现滚动效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了自定义view实现了类似百度手机助手,首页评论滚动效果。

看效果:

Android自定义ViewFlipper实现滚动效果

gif做的不好,其效果就是:几个viewitem不停的向上滚动,新加入item有个淡入的效果。

说下实现思路:自定义view继承至LinearLayout,控制item数量及其动画效果,实现item复用,传入数据即可,使用方便。

代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/**
 * Jiantao.Yang
 *
 * @description 仿百度手机助手,评论滚动效果
 * @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;
 
 //最后一个item动画
 private Animation mLastOneAnimation;
 
 //其它item动画
 private Animation mCommonAnimation;
 
 //数据下标
 private int mCurrentIndex;
 
 /**
  * 这里动画时间是1600毫秒,所以间隔得大于动画时间
  */
 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 数据count
   */
  public int getCount();
 
 }
 
}

再来看看调用部分:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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("测试数据:" + position);
  return item;
 }
 
 @Override
 public int getCount() {
  return 8;
 }
}

可以看出,MainActivity实现了ViewFlipper.IAdapter接口,setAdapter后调用startFlipper即可。

这里布局文件我就不贴出来了,附上工程源码,项目里动画时间有点长,修改下就ok。

限于水平有限,不足之处难免,望各位不舍指正,与君共勉。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/JianTao_Yang/article/details/43635169

延伸 · 阅读

精彩推荐