Android TV开发:实现3D仿Gallery效果的实例代码

时间:2021-08-15 06:59:56

本文讲述了Android TV开发:实现3D仿Gallery效果的实例代码。分享给大家供大家参考,具体如下:

1.实现效果

滚动翻页+ 页面点击+页码指示器+焦点控制

2.实现这个效果之前必须要了解

Android高级图片滚动控件实现3D版图片轮播器这篇文章,我是基于他的代码进行修改的,主要为了移植到电视上做了按键事件和焦点控制。

3.具体代码:

?
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
public class Image3DSwitchView extends LinearLayout {
 private int currentPage =0;//定义当前第几页
 /**
 * 图片左右两边的空白间距
 */
 public static final int IMAGE_PADDING = 5;
 private static final int TOUCH_STATE_REST = 0;
 private static final int TOUCH_STATE_SCROLLING = 1;
 /**
 * 滚动到下一张图片的速度
 */
 private static final int SNAP_VELOCITY = 600;
 
 /**
 * 表示滚动到下一张图片这个动作
 */
 private static final int SCROLL_NEXT = 0;
 /**
 * 表示滚动到上一张图片这个动作
 */
 private static final int SCROLL_PREVIOUS = 1;
 /**
 * 表示滚动回原图片这个动作
 */
 private static final int SCROLL_BACK = 2;
 private static Handler handler = new Handler();
 /**
 * 控件宽度
 */
 public static int mWidth;
 private VelocityTracker mVelocityTracker;//主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率
 private Scroller mScroller;
 /**
 * 图片滚动监听器,当图片发生滚动时回调这个接口
 */
 private OnImageSwitchListener mListener;
 /**
 * 记录当前的触摸状态
 */
 private int mTouchState = TOUCH_STATE_REST;
 /**
 * 记录被判定为滚动运动的最小滚动值
 */
 private int mTouchSlop;
 /**
 * 记录控件高度
 */
 private int mHeight;
 /**
 * 记录每张图片的宽度
 */
 private int mImageWidth;
 /**
 * 记录图片的总数量
 */
 private int mCount;
 /**
 * 记录当前显示图片的坐标
 */
 private int mCurrentImage;
 /**
 * 记录上次触摸的横坐标值
 */
 private float mLastMotionX;
 /**
 * 是否强制重新布局
 */
 private boolean forceToRelayout;
 private int[] mItems;
 public Image3DSwitchView(Context context, AttributeSet attrs) {
 super(context, attrs);
 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
 mScroller = new Scroller(context);
 //设置可以获得焦点
 setFocusable(true);
 }
 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 if (changed || forceToRelayout) {
 mCount = getChildCount();
 // 图片数量必须大于5,不然无法正常显示
 if (mCount < 5) {
 return;
 }
 mWidth = getMeasuredWidth();
 mHeight = getMeasuredHeight();
 // 每张图片的宽度设定为控件宽度的百分之六十
 mImageWidth = (int) (mWidth * 0.6);
 if (mCurrentImage >= 0 && mCurrentImage < mCount) {
 mScroller.abortAnimation();
 setScrollX(0);
 int left = -mImageWidth * 2 + (mWidth - mImageWidth) / 2;
 // 分别获取每个位置上应该显示的图片下标
 int[] items = {getIndexForItem(1), getIndexForItem(2),
 getIndexForItem(3), getIndexForItem(4),
 getIndexForItem(5)};
 mItems = items;
 // 通过循环为每张图片设定位置
 for (int i = 0; i < items.length; i++) {
 Image3DView childView = (Image3DView) getChildAt(items[i]);
 childView.layout(left + IMAGE_PADDING, 0, left
 + mImageWidth - IMAGE_PADDING, mHeight);
 childView.initImageViewBitmap();
 left = left + mImageWidth;
 }
 refreshImageShowing();
 }
 forceToRelayout = false;
 }
 }
 public interface OnFocusListener{
 void onFocus();
 void setValue(String value);
 }
 private OnFocusListener onFocusListener;
 public void setonFocusListener(OnFocusListener onFocusListener){
 this.onFocusListener = onFocusListener;
 }
 @Override
 public boolean dispatchKeyEvent(KeyEvent event) {
 if (event.getAction() == KeyEvent.ACTION_DOWN){
 switch (event.getKeyCode()){
 //按下键 响应回调
 case KeyEvent.KEYCODE_DPAD_DOWN:
 if (onFocusListener != null){onFocusListener.onFocus();}
 break;
 //按确定键
 case KeyEvent.KEYCODE_DPAD_CENTER:
 Toast.makeText(getContext(),"点击了图片"+(currentPage%7+1),Toast.LENGTH_SHORT).show();
 break;
 //右键
 case KeyEvent.KEYCODE_DPAD_RIGHT:
 scrollToNext();
 if (onFocusListener !=null){
 onFocusListener.setValue((currentPage%7+1)+"");
 }
 break;
 //左键
 case KeyEvent.KEYCODE_DPAD_LEFT:
 scrollToPrevious();
 if (onFocusListener !=null){
 onFocusListener.setValue((currentPage%7+1)+"");
 }
 break;
 }
 }
 return true;
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 if (mScroller.isFinished()) {
 if (mVelocityTracker == null) {
 mVelocityTracker = VelocityTracker.obtain();
 }
 mVelocityTracker.addMovement(event);
 int action = event.getAction();
 float x = event.getX();
 switch (action) {
 case MotionEvent.ACTION_DOWN:
 // 记录按下时的横坐标
 mLastMotionX = x;
 break;
 case MotionEvent.ACTION_MOVE:
 int disX = (int) (mLastMotionX - x);
 mLastMotionX = x;
 scrollBy(disX, 0);
 // 当发生移动时刷新图片的显示状态
 refreshImageShowing();
 break;
 case MotionEvent.ACTION_UP:
 mVelocityTracker.computeCurrentVelocity(1000);
 int velocityX = (int) mVelocityTracker.getXVelocity();
 if (shouldScrollToNext(velocityX)) {
 // 滚动到下一张图
 scrollToNext();
 } else if (shouldScrollToPrevious(velocityX)) {
 // 滚动到上一张图
 scrollToPrevious();
 } else {
 // 滚动回当前图片
 scrollBack();
 }
 if (mVelocityTracker != null) {
 mVelocityTracker.recycle();
 mVelocityTracker = null;
 }
 break;
 }
 }
 return true;
 }
 /**
 * 根据当前的触摸状态来决定是否屏蔽子控件的交互能力。
 */
 @Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
 int action = ev.getAction();
 if ((action == MotionEvent.ACTION_MOVE)
 && (mTouchState != TOUCH_STATE_REST)) {
 return true;
 }
 float x = ev.getX();
 switch (action) {
 case MotionEvent.ACTION_DOWN:
 mLastMotionX = x;
 mTouchState = TOUCH_STATE_REST;
 break;
 case MotionEvent.ACTION_MOVE:
 int xDiff = (int) Math.abs(mLastMotionX - x);
 if (xDiff > mTouchSlop) {
 mTouchState = TOUCH_STATE_SCROLLING;
 }
 break;
 case MotionEvent.ACTION_UP:
 default:
 mTouchState = TOUCH_STATE_REST;
 break;
 }
 return mTouchState != TOUCH_STATE_REST;
 }
 @Override
 public void computeScroll() {
 if (mScroller.computeScrollOffset()) {
 scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
 refreshImageShowing();
 postInvalidate();
 }
 }
 /**
 * 设置图片滚动的监听器,每当有图片滚动时会回调此接口。
 *
 * @param listener 图片滚动监听器
 */
 public void setOnImageSwitchListener(OnImageSwitchListener listener) {
 mListener = listener;
 }
 /**
 * 设置当前显示图片的下标,注意如果该值小于零或大于等于图片的总数量,图片则无法正常显示。
 *
 * @param currentImage 图片的下标
 */
 public void setCurrentImage(int currentImage) {
 mCurrentImage = currentImage;
 requestLayout();
 }
 /**
 * 滚动到下一张图片。
 */
 public void scrollToNext() {
 if (mScroller.isFinished()) {
 currentPage++;
 int disX = mImageWidth - getScrollX();
 checkImageSwitchBorder(SCROLL_NEXT);
 if (mListener != null) {
 mListener.onImageSwitch(mCurrentImage);
 }
 beginScroll(getScrollX(), 0, disX, 0, SCROLL_NEXT);
 }
 }
 /**
 * 滚动到上一张图片。
 */
 public void scrollToPrevious() {
 if (mScroller.isFinished()) {
 if (currentPage ==0){
 currentPage = 7;
 }else
 currentPage--;
 int disX = -mImageWidth - getScrollX();
 checkImageSwitchBorder(SCROLL_PREVIOUS);
 if (mListener != null) {
 mListener.onImageSwitch(mCurrentImage);
 }
 beginScroll(getScrollX(), 0, disX, 0, SCROLL_PREVIOUS);
 }
 }
 /**
 * 滚动回原图片。
 */
 public void scrollBack() {
 if (mScroller.isFinished()) {
 beginScroll(getScrollX(), 0, -getScrollX(), 0, SCROLL_BACK);
 }
 }
 /**
 * 回收所有图片对象,释放内存。
 */
 public void clear() {
 for (int i = 0; i < mCount; i++) {
 Image3DView childView = (Image3DView) getChildAt(i);
 childView.recycleBitmap();
 }
 }
 /**
 * 让控件中的所有图片开始滚动。
 */
 private void beginScroll(int startX, int startY, int dx, int dy,
 final int action) {
 int duration = (int) (700f / mImageWidth * Math.abs(dx));
 mScroller.startScroll(startX, startY, dx, dy, duration);
 invalidate();
 handler.postDelayed(new Runnable() {
 @Override
 public void run() {
 if (action == SCROLL_NEXT || action == SCROLL_PREVIOUS) {
 forceToRelayout = true;
 requestLayout();
 }
 }
 }, duration);
 }
 /**
 * 根据当前图片的下标和传入的item参数,来判断item位置上应该显示哪张图片。
 *
 * @param item 取值范围是1-5
 * @return 对应item位置上应该显示哪张图片。
 */
 private int getIndexForItem(int item) {
 int index = -1;
 index = mCurrentImage + item - 3;
 while (index < 0) {
 index = index + mCount;
 }
 while (index > mCount - 1) {
 index = index - mCount;
 }
 return index;
 }
 /**
 * 刷新所有图片的显示状态,包括当前的旋转角度。
 */
 private void refreshImageShowing() {
 for (int i = 0; i < mItems.length; i++) {
 Image3DView childView = (Image3DView) getChildAt(mItems[i]);
 childView.setRotateData(i, getScrollX());
 childView.invalidate();
 }
 }
 /**
 * 检查图片的边界,防止图片的下标超出规定范围。
 */
 private void checkImageSwitchBorder(int action) {
 if (action == SCROLL_NEXT && ++mCurrentImage >= mCount) {
 mCurrentImage = 0;
 } else if (action == SCROLL_PREVIOUS && --mCurrentImage < 0) {
 mCurrentImage = mCount - 1;
 }
 }
 /**
 * 判断是否应该滚动到下一张图片。
 */
 private boolean shouldScrollToNext(int velocityX) {
 return velocityX < -SNAP_VELOCITY || getScrollX() > mImageWidth / 2;
 }
 /**
 * 判断是否应该滚动到上一张图片。
 */
 private boolean shouldScrollToPrevious(int velocityX) {
 return velocityX > SNAP_VELOCITY || getScrollX() < -mImageWidth / 2;
 }
 /**
 * 图片滚动的监听器
 */
 public interface OnImageSwitchListener {
 /**
 * 当图片滚动时会回调此方法
 *
 * @param currentImage 当前图片的坐标
 */
 void onImageSwitch(int currentImage);
 }
}
?
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
public class Image3DView extends ImageView {
 /**
 * 旋转角度的基准值
 */
 private static final float BASE_DEGREE = 50f;
 /**
 * 旋转深度的基准值
 */
 private static final float BASE_DEEP = 150f;
 private Camera mCamera;
 private Matrix mMaxtrix;
 private Bitmap mBitmap;
 /**
 * 当前图片对应的下标
 */
 private int mIndex;
 /**
 * 在前图片在X轴方向滚动的距离
 */
 private int mScrollX;
 /**
 * Image3DSwitchView控件的宽度
 */
 private int mLayoutWidth;
 /**
 * 当前图片的宽度
 */
 private int mWidth;
 /**
 * 当前旋转的角度
 */
 private float mRotateDegree;
 /**
 * 旋转的中心点
 */
 private float mDx;
 /**
 * 旋转的深度
 */
 private float mDeep;
 public Image3DView(Context context, AttributeSet attrs) {
 super(context, attrs);
 mCamera = new Camera();
 mMaxtrix = new Matrix();
 //设置可获焦 & 可点击
 setFocusable(true);
 setClickable(true);
 }
 /**
 * 初始化Image3DView所需要的信息,包括图片宽度,截取背景图等。
 */
 public void initImageViewBitmap() {
 if (mBitmap == null) {
 //我们要获取cache首先要通过setDrawingCacheEnable方法开启cache,然后再调用getDrawingCache方法就可以获得view的cache图片了。
 setDrawingCacheEnabled(true);
 buildDrawingCache();
 mBitmap = getDrawingCache();
 }
 mLayoutWidth = Image3DSwitchView.mWidth;
 mWidth = getWidth() + Image3DSwitchView.IMAGE_PADDING * 2;
 }
 /**
 * 设置旋转角度。
 *
 * @param index 当前图片的下标
 * @param scrollX 当前图片在X轴方向滚动的距离
 */
 public void setRotateData(int index, int scrollX) {
 mIndex = index;
 mScrollX = scrollX;
 }
 /**
 * 回收当前的Bitmap对象,以释放内存。
 */
 public void recycleBitmap() {
 if (mBitmap != null && !mBitmap.isRecycled()) {
 mBitmap.recycle();
 }
 }
 @Override
 public void setImageResource(int resId) {
 super.setImageResource(resId);
 mBitmap = null;
 initImageViewBitmap();
 }
 @Override
 public void setImageBitmap(Bitmap bm) {
 super.setImageBitmap(bm);
 mBitmap = null;
 initImageViewBitmap();
 }
 @Override
 public void setImageDrawable(Drawable drawable) {
 super.setImageDrawable(drawable);
 mBitmap = null;
 initImageViewBitmap();
 }
 @Override
 public void setImageURI(Uri uri) {
 super.setImageURI(uri);
 mBitmap = null;
 initImageViewBitmap();
 }
 @Override
 protected void onDraw(Canvas canvas) {
 if (mBitmap == null) {
 // 如果Bitmap对象还不存在,先使用父类的onDraw方法进行绘制
 super.onDraw(canvas);
 } else {
 if (isImageVisible()) {
 // 绘图时需要注意,只有当图片可见的时候才进行绘制,这样可以节省运算效率
 computeRotateData();
 mCamera.save();
 mCamera.translate(0.0f, 0.0f, mDeep);
 mCamera.rotateY(mRotateDegree);
 mCamera.getMatrix(mMaxtrix);
 mCamera.restore();
 mMaxtrix.preTranslate(-mDx, -getHeight() / 2);
 mMaxtrix.postTranslate(mDx, getHeight() / 2);
 canvas.drawBitmap(mBitmap, mMaxtrix, null);
 }
 }
 }
 /**
 * 在这里计算所有旋转所需要的数据。
 */
 private void computeRotateData() {
 float degreePerPix = BASE_DEGREE / mWidth;
 float deepPerPix = BASE_DEEP / ((mLayoutWidth - mWidth) / 2);
 switch (mIndex) {
 case 0:
 mDx = mWidth;
 mRotateDegree = 360f - (2 * mWidth + mScrollX) * degreePerPix;
 if (mScrollX < -mWidth) {
 mDeep = 0;
 } else {
 mDeep = (mWidth + mScrollX) * deepPerPix;
 }
 break;
 case 1:
 if (mScrollX > 0) {
 mDx = mWidth;
 mRotateDegree = (360f - BASE_DEGREE) - mScrollX * degreePerPix;
 mDeep = mScrollX * deepPerPix;
 } else {
 if (mScrollX < -mWidth) {
 mDx = -Image3DSwitchView.IMAGE_PADDING * 2;
 mRotateDegree = (-mScrollX - mWidth) * degreePerPix;
 } else {
 mDx = mWidth;
 mRotateDegree = 360f - (mWidth + mScrollX) * degreePerPix;
 }
 mDeep = 0;
 }
 break;
 case 2:
 if (mScrollX > 0) {
 mDx = mWidth;
 mRotateDegree = 360f - mScrollX * degreePerPix;
 mDeep = 0;
 if (mScrollX > mWidth) {
 mDeep = (mScrollX - mWidth) * deepPerPix;
 }
 } else {
 mDx = -Image3DSwitchView.IMAGE_PADDING * 2;
 mRotateDegree = -mScrollX * degreePerPix;
 mDeep = 0;
 if (mScrollX < -mWidth) {
 mDeep = -(mWidth + mScrollX) * deepPerPix;
 }
 }
 break;
 case 3:
 if (mScrollX < 0) {
 mDx = -Image3DSwitchView.IMAGE_PADDING * 2;
 mRotateDegree = BASE_DEGREE - mScrollX * degreePerPix;
 mDeep = -mScrollX * deepPerPix;
 } else {
 if (mScrollX > mWidth) {
 mDx = mWidth;
 mRotateDegree = 360f - (mScrollX - mWidth) * degreePerPix;
 } else {
 mDx = -Image3DSwitchView.IMAGE_PADDING * 2;
 mRotateDegree = BASE_DEGREE - mScrollX * degreePerPix;
 }
 mDeep = 0;
 }
 break;
 case 4:
 mDx = -Image3DSwitchView.IMAGE_PADDING * 2;
 mRotateDegree = (2 * mWidth - mScrollX) * degreePerPix;
 if (mScrollX > mWidth) {
 mDeep = 0;
 } else {
 mDeep = (mWidth - mScrollX) * deepPerPix;
 }
 break;
 }
 }
 /**
 * 判断当前图片是否可见。
 *
 * @return 当前图片可见返回true,不可见返回false。
 */
 private boolean isImageVisible() {
 boolean isVisible = false;
 switch (mIndex) {
 case 0:
 if (mScrollX < (mLayoutWidth - mWidth) / 2 - mWidth) {
 isVisible = true;
 } else {
 isVisible = false;
 }
 break;
 case 1:
 if (mScrollX > (mLayoutWidth - mWidth) / 2) {
 isVisible = false;
 } else {
 isVisible = true;
 }
 break;
 case 2:
 if (mScrollX > mLayoutWidth / 2 + mWidth / 2
 || mScrollX < -mLayoutWidth / 2 - mWidth / 2) {
 isVisible = false;
 } else {
 isVisible = true;
 }
 break;
 case 3:
 if (mScrollX < -(mLayoutWidth - mWidth) / 2) {
 isVisible = false;
 } else {
 isVisible = true;
 }
 break;
 case 4:
 if (mScrollX > mWidth - (mLayoutWidth - mWidth) / 2) {
 isVisible = true;
 } else {
 isVisible = false;
 }
 break;
 }
 return isVisible;
 }
}
?
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
public class MainActivity extends AppCompatActivity {
 private Button btn;
 private Image3DSwitchView image3DSwitchView;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 btn = (Button) findViewById(R.id.btn);
 image3DSwitchView = (Image3DSwitchView) findViewById(R.id.image_switch_view);
 btn.setOnKeyListener(new View.OnKeyListener() {
 @Override
 public boolean onKey(View v, int keyCode, KeyEvent event) {
 if (keyCode == KeyEvent.KEYCODE_DPAD_UP && event.getAction()== KeyEvent.ACTION_DOWN)
 image3DSwitchView.requestFocus();
 return true;
 }
 });
 //设置监听,并实现接口
 image3DSwitchView.setonFocusListener(new Image3DSwitchView.OnFocusListener() {
 @Override
 public void onFocus() {
 btn.requestFocus();
 }
 @Override
 public void setValue(String value) {
 btn.setText(value+"/7");
 }
 
 });
 }
}
?
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
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="#000000">
 <com.example.rotate3d.Image3DSwitchView
 android:layout_marginTop="100dp"
 android:id="@+id/image_switch_view"
 android:layout_width="wrap_content"
 android:layout_height="470dp" >
 <com.example.rotate3d.Image3DView
 android:id="@+id/image1"
 android:focusable="true"
 android:focusableInTouchMode="true"
 android:clickable="true"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitXY"
 android:src="@drawable/image1" />
 <com.example.rotate3d.Image3DView
 android:id="@+id/image2"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitXY"
 android:src="@drawable/image2" />
 <com.example.rotate3d.Image3DView
 android:id="@+id/image3"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitXY"
 android:src="@drawable/image3" />
 <com.example.rotate3d.Image3DView
 android:id="@+id/image4"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitXY"
 android:src="@drawable/image4" />
 <com.example.rotate3d.Image3DView
 android:id="@+id/image5"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitXY"
 android:src="@drawable/image5" />
 <com.example.rotate3d.Image3DView
 android:id="@+id/image6"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitXY"
 android:src="@drawable/image6" />
 <com.example.rotate3d.Image3DView
 android:id="@+id/image7"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitXY"
 android:src="@drawable/image7" />
 </com.example.rotate3d.Image3DSwitchView>
 <Button
 android:id="@+id/btn"
 android:text="1/7"
 android:textSize="32dp"
 android:textColor="#ffffff"
 android:layout_below="@+id/image_switch_view"
 android:background="@drawable/button_style"
 android:layout_width="match_parent"
 android:layout_height="100dp" />
 
</RelativeLayout>

4.自己的成长点:

①响应遥控器按键事件:重写Image3DSwitchView类的dispatchKeyEvent()函数

?
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
@Override
 public boolean dispatchKeyEvent(KeyEvent event) {
 if (event.getAction() == KeyEvent.ACTION_DOWN){
 switch (event.getKeyCode()){
 //按下键 响应回调
 case KeyEvent.KEYCODE_DPAD_DOWN:
 if (onFocusListener != null){onFocusListener.onFocus();}
 break;
 //按确定键
 case KeyEvent.KEYCODE_DPAD_CENTER:
 Toast.makeText(getContext(),"点击了图片"+(currentPage%7+1),Toast.LENGTH_SHORT).show();
 break;
 //右键
 case KeyEvent.KEYCODE_DPAD_RIGHT:
 scrollToNext();
 if (onFocusListener !=null){
 onFocusListener.setValue((currentPage%7+1)+"");
 }
 break;
 //左键
 case KeyEvent.KEYCODE_DPAD_LEFT:
 scrollToPrevious();
 if (onFocusListener !=null){
 onFocusListener.setValue((currentPage%7+1)+"");
 }
 break;
 }
 }
 return true;
 }

注意:要能响应点击事件的前提必须是控件可以获得焦点,所以在构造函数中加上

?
1
setFocusable(true);

②回调机制:类似Android TV开发:使用RecycleView实现横向的Listview并响应点击事件的代码的原理。 越来越发现回调技术的好用:轻松通过接口函数里面的参数把动态变化的变量传递到mainActivity

?
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
public interface OnFocusListener{
 void onFocus();//处理焦点
 void setValue(String value);//处理当前页码
}
private OnFocusListener onFocusListener;
public void setonFocusListener(OnFocusListener onFocusListener){
 this.onFocusListener = onFocusListener;
<a target="_blank" href="http://www.zzvips.com/article/140153.htm">www.zzvips.com/article/140153.htm</a>}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
 if (event.getAction() == KeyEvent.ACTION_DOWN){
 switch (event.getKeyCode()){
 //按下键 响应回调
 case KeyEvent.KEYCODE_DPAD_DOWN:
 if (onFocusListener != null){onFocusListener.onFocus();}
 break;
 //按确定键
 case KeyEvent.KEYCODE_DPAD_CENTER:
 Toast.makeText(getContext(),"点击了图片"+(currentPage%7+1),Toast.LENGTH_SHORT).show();
 break;
 //右键
 case KeyEvent.KEYCODE_DPAD_RIGHT:
 scrollToNext();
 if (onFocusListener !=null){
 onFocusListener.setValue((currentPage%7+1)+"");
 }
 break;
 //左键
 case KeyEvent.KEYCODE_DPAD_LEFT:
 scrollToPrevious();
 if (onFocusListener !=null){
 onFocusListener.setValue((currentPage%7+1)+"");
 }
 break;
 }
 }
 return true;
}

在acitivity中调用

?
1
2
3
4
5
6
7
8
9
10
image3DSwitchView.setonFocusListener(new Image3DSwitchView.OnFocusListener() {
 @Override
 public void onFocus() {
 btn.requestFocus();//让Image3DSwitchView控件下的按钮获得焦点
 }
 @Override
 public void setValue(String value) {
 btn.setText(value+"/7");//给按钮设置 第几页/共几页
 }
 });

5.源码+apk下载地址

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

原文链接:https://blog.csdn.net/meetings/article/details/52950204