SeniorUI_高级UI汇总目录
SeniorUI34_maven项目生成java的两种方法
1 效果图
2 需求
实现一群圆形物体重力环境下 掉落、碰撞运动效果
3 分析
- 引进jbox库,实现运动碰撞效果
- 自定义一个ViewGroup,所有物体即它的childView在这里面运动,
- 定义一个jbox API下的控制实现类JboxImpl,是对现实世界即ViewGroup的映射
- 将ViewGroup的参数传到JboxImpl中,创建世界的边缘,确定四周不能动的边框-刚体
- 将ViewGrope的child映射到JboxImpl中,创建不同的可以移动的Body
- 监听重力感应,将感应的参数通过ViewGroup传到JboxImpl世界中,从而获取对应每个刚体的的坐标
- 将坐标设置到对应tag的View中去,通知ViewGroup重绘
4 主要代码
JboxImpl
public class JboxImpl {
private static final String TAG = "tim@" + JboxImpl.class.getSimpleName();
private World mWorld; //模拟世界
private float dt = 1f/60f; //模拟世界的频率
private int mVelocityIterations = 5; //速率迭代器
private int mPosiontIterations = 20; //迭代次数
private int mWidth,mHeight;
private float mDesity = 0.5f;
private float mRatio = 50;//坐标映射比例
private final Random mRandom = new Random();
public JboxImpl(float desity) {
mDesity = desity;
}
public void setWorlSize(int width, int height) {
mHeight = height;
mWidth = width;
}
public void startWorld() {
if (mWorld != null) {
mWorld.step(dt, mVelocityIterations, mPosiontIterations);
}
}
public void createWorld() {
if (mWorld == null) {
mWorld = new World(new Vec2(0, 10.0f));
updateVertiacalBounds();
updateHorizontalBounds();
}
}
public void creatBody(View view) {
BodyDef bodyDef = new BodyDef();
bodyDef.setType(BodyType.DYNAMIC);
bodyDef.position.set(switchPositionToBody( view.getX() + (view.getWidth() / 2) )
,switchPositionToBody(view.getY() + (view.getHeight() / 2)) );
Shape shape = null;
Boolean isCircle = (Boolean) view.getTag(R.id.dn_view_circle_tag);
if (isCircle != null && isCircle) {
shape = craeteCircleShape( switchPositionToBody(view.getWidth() / 2) );
} else {
Log.i(TAG,"createBody veiw tag is not circle!!!");
return;
}
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.setShape(shape);
fixtureDef.friction = 0.8f;//摩擦系数
fixtureDef.density = mDesity;
fixtureDef.restitution = 0.5f;//补偿系数
Body body = mWorld.createBody(bodyDef);
body.createFixture(fixtureDef);
view.setTag(R.id.dn_view_body_tag, body);
body.setLinearVelocity(new Vec2(mRandom.nextFloat(), mRandom.nextFloat()));
}
//创建圆形
private Shape craeteCircleShape(float radius) {
CircleShape circleShape = new CircleShape();
circleShape.setRadius(radius);
return circleShape;
}
private void updateVertiacalBounds() {
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.STATIC; //定义静止的刚体
PolygonShape box = new PolygonShape(); //定义的形状
float boxWidth = switchPositionToBody(mWidth);
float boxHeight = switchPositionToBody(mRatio);
box.setAsBox(boxWidth, boxHeight); //确定为矩形
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = box;
fixtureDef.density = mDesity;
fixtureDef.friction = 0.8f;//摩擦系数
fixtureDef.restitution = 0.5f; //补偿系数
bodyDef.position.set(0, -boxHeight);
Body topBody = mWorld.createBody(bodyDef); //创建一个真实的上边 body
topBody.createFixture(fixtureDef);
bodyDef.position.set(0, switchPositionToBody(mHeight) + boxHeight);
Body bottomBody = mWorld.createBody(bodyDef);
bottomBody.createFixture(fixtureDef);
}
private void updateHorizontalBounds() {
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.STATIC; //定义静止的刚体
PolygonShape box = new PolygonShape(); //定义的形状
float boxWidth = switchPositionToBody(mRatio);
float boxHeight = switchPositionToBody(mHeight);
box.setAsBox(boxWidth, boxHeight); //确定为矩形
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = box;
fixtureDef.density = mDesity;
fixtureDef.friction = 0.8f;//摩擦系数
fixtureDef.restitution = 0.5f; //补偿系数
bodyDef.position.set(-boxWidth, 0);
Body leftBody = mWorld.createBody(bodyDef); //创建一个真实的上边 body
leftBody.createFixture(fixtureDef);
bodyDef.position.set(switchPositionToBody(mWidth) + boxWidth, 0);
Body rightBody = mWorld.createBody(bodyDef);
rightBody.createFixture(fixtureDef);
}
//view坐标映射为物理的坐标
private float switchPositionToBody(float viewPosition) {
return viewPosition / mRatio;
}
//物理的坐标映射为iew坐标映射
private float switchPositionToView(float bodyPosition) {
return bodyPosition * mRatio;
}
public boolean isBodyView(View view) {
Body body = (Body) view.getTag(R.id.dn_view_body_tag);
return body != null;
}
public float getViewX(View view) {
Body body = (Body) view.getTag(R.id.dn_view_body_tag);
if (body != null) {
return switchPositionToView(body.getPosition().x ) - (view.getWidth() / 2);
}
return 0;
}
public float getViewY(View view) {
Body body = (Body) view.getTag(R.id.dn_view_body_tag);
if (body != null) {
return switchPositionToView(body.getPosition().y ) - (view.getHeight() / 2);
}
return 0;
}
public float getViewRotaion(View view) {
Body body = (Body) view.getTag(R.id.dn_view_body_tag);
if (body != null) {
float angle = body.getAngle();
return (angle / 3.14f * 180f) % 360;
}
return 0;
}
public void applyLinearImpulse(float x, float y, View view) {
Body body = (Body) view.getTag(R.id.dn_view_body_tag);
Vec2 impluse = new Vec2(x,y);
body.applyLinearImpulse(impluse, body.getPosition(), true); //给body做线性运动 true 运动完之后停止
}
}
CollisionView
public class CollisionView extends FrameLayout{
private JboxImpl jboxImpl;
public CollisionView(@NonNull Context context) {
this(context,null);
}
public CollisionView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CollisionView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
initView();
}
private void initView() {
jboxImpl = new JboxImpl(getResources().getDisplayMetrics().density);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
jboxImpl.setWorlSize(w,h);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
jboxImpl.createWorld();
//子viwe创建tag 设置body
int childCount = getChildCount();
for (int i =0; i< childCount; i++) {
View view = getChildAt(i);
if (!jboxImpl.isBodyView(view) || changed) {
jboxImpl.creatBody(view);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
jboxImpl.startWorld();
int childCount = getChildCount();
for (int i =0; i< childCount; i++) {
View view = getChildAt(i);
if (jboxImpl.isBodyView(view)) {
view.setX(jboxImpl.getViewX(view));
view.setY(jboxImpl.getViewY(view));
view.setRotation(jboxImpl.getViewRotaion(view));
}
}
invalidate();
}
public void onSensorChanged(float x, float y) {
int childCount = getChildCount();
for (int i =0; i< childCount; i++) {
View view = getChildAt(i);
if (jboxImpl.isBodyView(view)) {
jboxImpl.applyLinearImpulse(x,y,view);
}
}
}
}
使用:JboxActivity
public class JboxActivity extends FragmentActivity implements SensorEventListener {
private SensorManager sensorManager;
private Sensor defaultSensor;
private CollisionView collisionView;
private int[] imgs = {
R.drawable.share_fb,
R.drawable.share_kongjian,
R.drawable.share_pyq,
R.drawable.share_qq,
R.drawable.share_tw,
R.drawable.share_wechat,
R.drawable.share_weibo
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.jbox_activity);
}
@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, defaultSensor, SensorManager.SENSOR_DELAY_UI);
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
@Override
public void onContentChanged() {
collisionView = (CollisionView) findViewById(R.id.jbox_view);
initView();
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
private void initView() {
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER;
for (int i = 0; i < imgs.length; i++) {
ImageView imageView = new ImageView(this);
imageView.setImageResource(imgs[i]);
imageView.setTag(R.id.dn_view_circle_tag, true);
collisionView.addView(imageView,layoutParams);
}
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x = event.values[0];
float y = event.values[1] * 2.0f;
collisionView.onSensorChanged(-x, y);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}