说明:之前在网上到处搜寻类似的旋转效果 但搜到的结果都不是十分满意 原因不多追述(如果有人找到过相关 比较好的效果 可以发一下连接 一起共同进步)
一 效果展示 :
如非您所需要的效果 也希望能给些微帮助
具体操作以及实现 效果 请看项目例子
二 使用方式
此空间继承与FrameLayout
子空间直接添加如同framelayout 相同 如要如图效果 唯一要求子空间必须位于父控件中心且宽高等大小 为了方便扩展而做 如有其他需求可自行更改 (注 所有子控件 最好添加上背景 由于绘制机制和动画原因 没有背景会有部分重贴) 内部子view 可为 任意ViewGroup 。 弱使用过程中遇见任何BUG 欢迎提出。
三 实现原理
实现原理由Camera 与Maxtrix 组合修改View的绘制而得 具体Camera 与Maxtrix 的变换 过程请自行搜索。 在此不班门弄斧。
具体修改有
1
2
3
4
5
6
7
8
9
10
11
|
@Override
protected void dispatchDraw(Canvas canvas) {
int indexleft = getWidth() / 2 ; //中间显示视图 ----左边的位置
int postTranslateX = rotationX * childWith / 2 / rotation; //设-----定边移动 距离
//定点 又称顶点
// chilDrawforCamera(canvas, postTranslateX, indexleft, 3);//预绘制 的 县绘制 防止遮挡
for ( int i = 0 ; i < 4 ; i++)
chilDrawforCamera(canvas, postTranslateX, indexleft, i);
if (!isTouch)
handler.sendEmptyMessageDelayed( 1 , 100 );
}
|
重新编写 dispathDraw() 从而达到 不必要去修改子view的内容 而添加扩展性
具体变换包括
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
|
private void chilDrawforCamera(Canvas canvas, int postTranslateX, int indexleft, int i) {
canvas.save();
mCamera.save();
mMaxtrix.reset();
mCamera.translate(postTranslateX, 0 , 0 );
mCamera.rotateY(rotationX);
mCamera.translate(postTranslateX, 0 , 0 );
if (postTranslateX == 0 ) {
if (isright)
setCameraChange(childWith, rotation, i);
else
setCameraChange(-childWith, -rotation, i);
} else if (postTranslateX > 0 ) {
setCameraChange(childWith, rotation, i);
} else if (postTranslateX < 0 ) {
setCameraChange(-childWith, -rotation, i);
}
mCamera.getMatrix(mMaxtrix);
mCamera.restore();
mMaxtrix.preTranslate(-indexleft, -getHeight() / 2 ); //指定在 屏幕上 运行的棱 是哪一条
mMaxtrix.postTranslate(indexleft, getHeight() / 2 ); //运行路径
canvas.concat(mMaxtrix);
//绘制
View childAt = getChildAt((swithView(i) + 2 * getChildCount()) % getChildCount());
drawChild(canvas, childAt, 0 );
canvas.restore();
}
|
指定需要绘制的子view 先后顺序以及哪些子view
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
|
private int swithView( int i) {
int k = 0 ;
switch (i) {
case 0 :
if (isright)
k = index - 2 ;
else
k = index + 2 ;
break ;
case 1 :
if (isright)
k = index + 1 ;
else
k = index - 1 ;
break ;
case 2 :
if (isright)
k = index - 1 ;
else
k = index + 1 ;
break ;
case 3 :
k = index;
break ;
}
return k;
|
具体的网上其他 类似效果到底有什么不同于优势在此不多做描述 实现方式上有哪些不同 嗯 下次有空再细说(由于需要大量图文描述 3D的变换过程才讲的清楚,有些间隔的时间也稍长 只记得大概的思路过程)。
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
|
private void setCameraChange( int translate, int roat, int i) {
switch (i) {
case 0 :
//预绘制 的VIEW
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.rotateY(-roat);
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.rotateY(-roat);
mCamera.translate(-translate / 2 , 0 , 0 );
break ;
//当前位置两侧的View
case 1 :
mCamera.translate(translate / 2 , 0 , 0 );
mCamera.rotateY(roat);
mCamera.translate(translate / 2 , 0 , 0 );
break ;
case 2 :
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.rotateY(-roat);
mCamera.translate(-translate / 2 , 0 , 0 );
break ;
//最后绘制 当前显示位置 防止 被遮挡
case 3 :
mCamera.rotateY( 0 );
break ;
}
}
|
其他剩下的就是 index 选中切换 以及滑动内容 和分发修改等。demo下载 有分的相关小伙伴就下载提供一些 没有的就github 下载吧。
整个类复制也可以
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
|
package com.burning.foethedog;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
* Created by burning on 2017/5/2.
* When I wrote this, only God and I understood what I was doing
* Now, God only knows
* -------------------------//┏┓ ┏┓
* -------------------------//┏┛┻━━━┛┻┓
* -------------------------//┃ ┃
* -------------------------//┃ ━ ┃
* -------------------------//┃ ┳┛ ┗┳ ┃
* -------------------------//┃ ┃
* -------------------------//┃ ┻ ┃
* -------------------------//┃ ┃
* -------------------------//┗━┓ ┏━┛
* -------------------------//┃ ┃ 神兽保佑
* -------------------------//┃ ┃ 代码无BUG!
* -------------------------//┃ ┗━━━┓
* -------------------------//┃ ┣┓
* -------------------------//┃ ┏┛
* -------------------------//┗┓┓┏━┳┓┏┛
* -------------------------// ┃┫┫ ┃┫┫
* -------------------------// ┗┻┛ ┗┻┛
*/
public class Rota3DSwithView extends FrameLayout {
Camera mCamera;
Matrix mMaxtrix;
public Rota3DSwithView(Context context) {
super (context);
initRoat3D();
}
private void initRoat3D() {
mCamera = new Camera();
mMaxtrix = new Matrix();
setWillNotDraw( false );
}
public Rota3DSwithView(Context context, AttributeSet attrs) {
super (context, attrs);
initRoat3D();
}
public Rota3DSwithView(Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
initRoat3D();
}
public Rota3DSwithView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super (context, attrs, defStyleAttr, defStyleRes);
initRoat3D();
}
int childWith;
@Override
protected void onLayout( boolean changed, int left, int top, int right, int bottom) {
childWith = getChildAt( 0 ).getMeasuredWidth();
super .onLayout(changed, left, top, right, bottom);
}
//摄像机 为点光源 正真的直角 反而看起来 并不是直角
static int rotation = 60 ; // 设定外角
int rotationX = 00 ;
int index = 0 ;
@Override
protected void dispatchDraw(Canvas canvas) {
int indexleft = getWidth() / 2 ; //中间显示视图 ----左边的位置
int postTranslateX = rotationX * childWith / 2 / rotation; //设-----定边移动 距离
//定点 又称顶点
// chilDrawforCamera(canvas, postTranslateX, indexleft, 3);//预绘制 的 县绘制 防止遮挡
for ( int i = 0 ; i < 4 ; i++)
chilDrawforCamera(canvas, postTranslateX, indexleft, i);
if (!isTouch)
handler.sendEmptyMessageDelayed( 1 , 100 );
}
private void setCameraChange( int translate, int roat, int i) {
switch (i) {
case 0 :
//预绘制 的VIEW
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.rotateY(-roat);
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.rotateY(-roat);
mCamera.translate(-translate / 2 , 0 , 0 );
break ;
//当前位置两侧的View
case 1 :
mCamera.translate(translate / 2 , 0 , 0 );
mCamera.rotateY(roat);
mCamera.translate(translate / 2 , 0 , 0 );
break ;
case 2 :
mCamera.translate(-translate / 2 , 0 , 0 );
mCamera.rotateY(-roat);
mCamera.translate(-translate / 2 , 0 , 0 );
break ;
//最后绘制 当前显示位置 防止 被遮挡
case 3 :
mCamera.rotateY( 0 );
break ;
}
}
boolean isright = false ;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1 :
if (isTouch)
return ;
if (isright)
rotationX++;
else
rotationX--;
if (Math.abs(rotationX) == rotation) {
rotationX = 0 ;
index = index % getChildCount();
if (isright)
index--;
else
index++;
}
Rota3DSwithView. this .invalidate();
break ;
}
}
};
private void chilDrawforCamera(Canvas canvas, int postTranslateX, int indexleft, int i) {
canvas.save();
mCamera.save();
mMaxtrix.reset();
mCamera.translate(postTranslateX, 0 , 0 );
mCamera.rotateY(rotationX);
mCamera.translate(postTranslateX, 0 , 0 );
if (postTranslateX == 0 ) {
if (isright)
setCameraChange(childWith, rotation, i);
else
setCameraChange(-childWith, -rotation, i);
} else if (postTranslateX > 0 ) {
setCameraChange(childWith, rotation, i);
} else if (postTranslateX < 0 ) {
setCameraChange(-childWith, -rotation, i);
}
mCamera.getMatrix(mMaxtrix);
mCamera.restore();
mMaxtrix.preTranslate(-indexleft, -getHeight() / 2 ); //指定在 屏幕上 运行的棱 是哪一条
mMaxtrix.postTranslate(indexleft, getHeight() / 2 ); //运行路径
canvas.concat(mMaxtrix);
//绘制
View childAt = getChildAt((swithView(i) + 2 * getChildCount()) % getChildCount());
drawChild(canvas, childAt, 0 );
canvas.restore();
}
private int swithView( int i) {
int k = 0 ;
switch (i) {
case 0 :
if (isright)
k = index - 2 ;
else
k = index + 2 ;
break ;
case 1 :
if (isright)
k = index + 1 ;
else
k = index - 1 ;
break ;
case 2 :
if (isright)
k = index - 1 ;
else
k = index + 1 ;
break ;
case 3 :
k = index;
break ;
}
return k;
}
boolean isTouch = false ;
int downX = 0 ;
public boolean dispatchTouchEvent(MotionEvent event) {
//这里我们就 就只分发给当前index子View
isTouch = event.getAction() == MotionEvent.ACTION_MOVE;
if (!onInterceptTouchEvent(event)) {
index = index % getChildCount();
return getChildAt((index + getChildCount()) % getChildCount()).dispatchTouchEvent(event);
}
return super .dispatchTouchEvent(event);
}
int thisRx = 0 ;
int thisindex;
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = ( int ) event.getX();
thisindex = index;
thisRx = rotationX;
break ;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - downX) > 50 ) {
return true /*onTouchEvent(event)*/ ;
}
break ;
}
return false ;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int moveX = 0 ;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = ( int ) event.getX();
break ;
case MotionEvent.ACTION_MOVE:
handler.removeCallbacksAndMessages( null );
// isTouch = true;
moveX = ( int ) event.getX() - downX;
int moveRx = thisRx + moveX * rotation * 2 / (getWidth() + 100 );
isright = (moveRx > 0 ) ? true : false ;
int addindex = moveRx / rotation;
index = thisindex - addindex;
rotationX = moveRx % rotation;
System.out.println( "===thisRx===" + thisRx + "===moveRx===" + moveRx + "=========addindex=" + addindex);
Rota3DSwithView. this .invalidate();
break ;
case MotionEvent.ACTION_UP:
System.out.println( "===ACTION_UP===" );
// isTouch = false;
handler.removeCallbacksAndMessages( null );
Rota3DSwithView. this .invalidate();
break ;
}
return true ;
}
public void destory() {
handler.removeCallbacksAndMessages( null );
handler = null ;
}
}
|
github下载地址
如有疑问可私信交流^_^
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://blog.csdn.net/xkyh941/article/details/79625458