公司的手机OS升级,在最新的Camera拟用这样的交互。感觉还不错。
思路:
1.ViewGroup中包含imageView按钮,根据显示的个数动态计算布局,在onLayout中重新排布ImageView的位置。
2.重新排布ImageView的位置的时候使用动画,动画需要坐标即需要自定义ImageView添加位置属性。
3.提供给外界方法用以决定显示哪个按钮,显示几个。
下面先来给imageView控件添加坐标属性。
public class ItemView extends ImageView
{
private int mLastStaus = View.VISIBLE;
private float mLastPosition = 0;
private float mCurrentPosition = 0;
public ItemView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
public ItemView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ItemView(Context context)
{
super(context);
}
public float getmLastPosition()
{
return mLastPosition;
}
public void setmLastPosition(float mLastPosition)
{
this.mLastPosition = mLastPosition;
}
/**
* @return the mLastStaus
*/
public int getmLastStaus()
{
return mLastStaus;
}
/**
* @param mLastStaus the mLastStaus to set
*/
public void setmLastStaus(int mLastStaus)
{
this.mLastStaus = mLastStaus;
}
/**
* @return the mCurrentPosition
*/
public float getmCurrentPosition()
{
return mCurrentPosition;
}
/**
* @param mCurrentPosition the mCurrentPosition to set
*/
public void setmCurrentPosition(float mCurrentPosition)
{
this.mCurrentPosition = mCurrentPosition;
}
}
现在imageView已经有了mLastPosition mCurrentPosition 这个的位置属性。
现在定义ViewGroup以动态添加删除按钮。新控件继承LinearLayout方便实现
JPowerTranslateView extends LinearLayout
然后在XML中添加控件及按钮
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal"
android:layout_alignParentTop="true">
<Button
android:id="@+id/button1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button1"/>
<Button
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button2"/>
</LinearLayout>
<com.ws.jpower.animation.JPowerTranslateView
android:id="@+id/animation_main_view"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#50ffffff"
android:orientation="horizontal"
android:layout_centerInParent="true">
<com.ws.jpower.animation.ItemView
android:id="@+id/image_btn1"
android:layout_width="80dp"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/ic_lava_flash_auto_normal"/>
<com.ws.jpower.animation.ItemView
android:id="@+id/image_btn2"
android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@drawable/lava_hdr_auto_normal"
android:scaleType="center"/>
<com.ws.jpower.animation.ItemView
android:id="@+id/image_btn3"
android:layout_width="80dp"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/lava_shutter_type_gesture_5s_normal"/>
<com.ws.jpower.animation.ItemView
android:id="@+id/image_btn4"
android:layout_width="80dp"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/lava_switch_camera_normal"
android:visibility="gone"/>
</com.ws.jpower.animation.JPowerTranslateView>
</RelativeLayout>
布局添加完后,在onFinishInflate方法中把GONE与VISIBLE的View分别放进不同的ArrayList
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
mGoneView = new ArrayList<ItemView>();
mVisibledView = new ArrayList<ItemView>();
mVisibleView = new ArrayList<ItemView>();
for (int i = 0; i < getChildCount(); i++)
{
if (getChildAt(i).getVisibility() == View.GONE)
{
mGoneView.add((ItemView) getChildAt(i));
} else
{
mVisibledView.add((ItemView) getChildAt(i));
mVisibleView.add((ItemView) getChildAt(i));
}
}
}
然后根据需要显示的View,从新排布
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
if (mWidth == 0)
{
mWidth = mDisplayWith;
}
}
//排布子View
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
super.onLayout(changed, l, t, r, b);
if (mVisibleView != null && mVisibleView.size() > 0)
{
int visibleCount = mVisibleView.size();//需要显示View的数量
itemWidth = mWidth / visibleCount; //等分父容器
for (int i = 0; i < visibleCount; i++)
{
int itemWh = 0;
ItemView itemView = mVisibleView.get(i);
itemWh = itemView.getWidth();
if (itemWh == 0)
{
itemWh = 80;
}
int maginLeft = itemWidth * i + (itemWidth - itemWh) / 2;//子View的left坐标,即把每个子View放置在每份的中间
itemView.layout(maginLeft, itemView.getTop(), maginLeft + itemWh, itemView.getBottom());
itemView.setmLastPosition(maginLeft);//保存位置信息,便于后期根据坐标做动画 LastPosition
}
}
}
给外界提供一个方法,动态隐藏添加按钮。
先回顾一下动画demo
// 原始平移动画TranslateAnimation
private Animation getAnimation(float fromXValue, float toXValue, float fromYValue, float toYValue, long duration)
{
/*TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
float fromXDelta 动画开始的点离当前View X坐标上的差值
float toXDelta 动画结束的点离当前View X坐标上的差值
float fromYDelta 动画开始的点离当前View Y坐标上的差值
float toYDelta 动画开始的点离当前View Y坐标上的差值*/
TranslateAnimation animation = new TranslateAnimation(fromXValue, toXValue, fromYValue, toYValue);
animation.setDuration(duration);
animation.setInterpolator(new AccelerateInterpolator());
return animation;
}
// 属性动画PropertyValuesHolder
public void propertyValuesHolder(View view, float fromXValue, float toXValue, float fromYValue, float toYValue, long duration)
{
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationX", fromXValue, toXValue);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", fromYValue, toYValue);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY);
animator.setDuration(duration).start();
animator.addListener(new AnimatorListenerAdapter()
{
@Override
public void onAnimationEnd(Animator animation)
{
}
});
}
// 属性动画ObjectAnimator,AnimatorSet
public void togetherAnimator(View view)
{
ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 2f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(view, "rotation", 1.0f, 2f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(2000);
animSet.setInterpolator(new LinearInterpolator());
// 两个动画同时执行
animSet.playTogether(anim1, anim2);
animSet.start();
}
updateView方法
//status数组决定哪个View是显示的,visibleCount决定要显示的数目
public void updateView(boolean[] status, int visibleCount)
{
Log.e("updateView", "updateView start ");
mGoneView = new ArrayList<ItemView>();
mVisibledView = new ArrayList<ItemView>();
mVisiblingView = new ArrayList<ItemView>();
mVisibleView = new ArrayList<ItemView>();
itemWidth = mWidth / visibleCount;//重新计算每份的长度
Log.e("updateView", "onLayout itemWidth = " + itemWidth);
Log.e("updateView", "onLayout visibleCount = " + visibleCount);
int count = 0;
for (int i = 0; i < status.length; i++)
{
final ItemView itemView = (ItemView) getChildAt(i);
if (status[i])//根据boolean,这是要显示的View
{
int itemWh = 0;
itemWh = itemView.getWidth();
if (itemWh == 0)
{
itemWh = 80;
}
int maginLeft = itemWidth * count + (itemWidth - itemWh) / 2;//View的left坐标
count++;
itemView.setmCurrentPosition(maginLeft);//保存位置信息,便于后期根据坐标做动画 CurrentPosition
Log.e("updateView", "updateView setmCurrentPosition " + maginLeft + " , i = " + i);
if (itemView.getVisibility() == View.VISIBLE)
{
// ((ItemView)getChildAt(i)).setmLastPosition(getChildAt(i).getLeft());
Log.e("updateView", "updateView getChildAt(i).getLeft() " + itemView.getLeft() + " , i = " + i);
mVisibledView.add(itemView);//已经显示了,本来就是显示的
} else
{
mVisiblingView.add(itemView);//本来没显示,这次要显示的
}
mVisibleView.add(itemView);
} else
{
mGoneView.add(itemView);//本次需要隐藏的
if (itemView.getVisibility() != View.GONE)
{
itemView.setVisibility(View.GONE);
}
}
}
//准备完数据后开始动画
for (int i = 0; i < mVisibleView.size(); i++)
{
if (mVisibledView.contains(mVisibleView.get(i))) //本来就显示的做平移动画
{
Log.e("updateView", "updateView getChildAt(i).getmCurrentPosition() " + mVisibleView.get(i).getmCurrentPosition());
Log.e("updateView", "updateView getChildAt(i).getmLastPosition() " + mVisibleView.get(i).getmLastPosition());
ObjectAnimator
.ofFloat(mVisibleView.get(i), "translationX",
(mVisibleView.get(i).getmLastPosition() - mVisibleView.get(i).getmCurrentPosition()), 0f).setDuration(500).start();
} else//未显示的setVisibility(View.VISIBLE)
{
mVisibleView.get(i).setVisibility(View.VISIBLE);
AlphaAnimation mAlphaAnimation = new AlphaAnimation(0.0f, 1.0f);
mAlphaAnimation.setDuration(200);
mAlphaAnimation.setInterpolator(new AccelerateInterpolator());
mVisibleView.get(i).startAnimation(mAlphaAnimation);
}
}
Log.e("updateView", "updateView end ");
}
下面是使用demo:
public class AnimationActivity extends Activity
{
private Button button1 = null;
private Button button2 = null;
private JPowerTranslateView mJPowerTranslateView;
boolean isReset = false;
boolean isReset2 = false;
int visibleCount = 4;
@Override
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_activity);
mJPowerTranslateView = (JPowerTranslateView) findViewById(R.id.animation_main_view);
mJPowerTranslateView.setBackgroundResource(R.drawable.lava_pro_single_settings_bg);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button1.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
boolean status[] =
{ true, true, false, true };
boolean reset[] =
{ true, true, true, true };
if (isReset)
{
mJPowerTranslateView.updateView(status, 3);
isReset = false;
} else
{
isReset = true;
mJPowerTranslateView.updateView(reset, 4);
}
// mJPowerTranslateView.updateView();
}
});
button2.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
boolean status[] =
{ true, false, true, false };
boolean reset[] =
{ false, true, false, false };
if (isReset)
{
mJPowerTranslateView.updateView(status, 2);
isReset = false;
} else
{
mJPowerTranslateView.updateView(reset, 1);
isReset = true;
}
// mJPowerTranslateView.updateView();
}
});
}
}
JPowerTranslateView 完整代码
import java.util.ArrayList;
import java.util.List;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class JPowerTranslateView extends LinearLayout
{
private int mDisplayWith = 720;
private int mWidth = 720;
private int itemWidth;
int visibleCount = 4;
private List<ItemView> mGoneView = null;
private List<ItemView> mVisibledView = null;
private List<ItemView> mVisiblingView = null;
private List<ItemView> mVisibleView = null;
public JPowerTranslateView(Context context)
{
super(context, null);
}
public JPowerTranslateView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public JPowerTranslateView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mDisplayWith = wm.getDefaultDisplay().getWidth();
}
//初始化 把GONE与VISIBLE的View分别放进不同的ArrayList
@Override
protected void onFinishInflate()
{
// TODO Auto-generated method stub
super.onFinishInflate();
mGoneView = new ArrayList<ItemView>();
mVisibledView = new ArrayList<ItemView>();
mVisibleView = new ArrayList<ItemView>();
for (int i = 0; i < getChildCount(); i++)
{
if (getChildAt(i).getVisibility() == View.GONE)
{
mGoneView.add((ItemView) getChildAt(i));
} else
{
mVisibledView.add((ItemView) getChildAt(i));
mVisibleView.add((ItemView) getChildAt(i));
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
if (mWidth == 0)
{
mWidth = mDisplayWith;
}
}
//排布子View
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
super.onLayout(changed, l, t, r, b);
if (mVisibleView != null && mVisibleView.size() > 0)
{
int visibleCount = mVisibleView.size();//需要显示View的数量
itemWidth = mWidth / visibleCount; //等分父容器
for (int i = 0; i < visibleCount; i++)
{
int itemWh = 0;
ItemView itemView = mVisibleView.get(i);
itemWh = itemView.getWidth();
if (itemWh == 0)
{
itemWh = 80;
}
int maginLeft = itemWidth * i + (itemWidth - itemWh) / 2;//子View的left坐标,即把每个子View放置在每份的中间
itemView.layout(maginLeft, itemView.getTop(), maginLeft + itemWh, itemView.getBottom());
itemView.setmLastPosition(maginLeft);//保存位置信息,便于后期根据坐标做动画 LastPosition
}
}
}
//status数组决定哪个View是显示的,visibleCount决定要显示的数目
public void updateView(boolean[] status, int visibleCount)
{
Log.e("updateView", "updateView start ");
mGoneView = new ArrayList<ItemView>();
mVisibledView = new ArrayList<ItemView>();
mVisiblingView = new ArrayList<ItemView>();
mVisibleView = new ArrayList<ItemView>();
itemWidth = mWidth / visibleCount;//重新计算每份的长度
int count = 0;
for (int i = 0; i < status.length; i++)
{
final ItemView itemView = (ItemView) getChildAt(i);
if (status[i])//根据boolean,这是要显示的View
{
int itemWh = 0;
itemWh = itemView.getWidth();
if (itemWh == 0)
{
itemWh = 80;
}
int maginLeft = itemWidth * count + (itemWidth - itemWh) / 2;//View的left坐标
count++;
itemView.setmCurrentPosition(maginLeft);//保存位置信息,便于后期根据坐标做动画 CurrentPosition
if (itemView.getVisibility() == View.VISIBLE)
{
// ((ItemView)getChildAt(i)).setmLastPosition(getChildAt(i).getLeft());
mVisibledView.add(itemView);//已经显示了,本来就是显示的
} else
{
mVisiblingView.add(itemView);//本来没显示,这次要显示的
}
mVisibleView.add(itemView);
} else
{
mGoneView.add(itemView);//本次需要隐藏的
if (itemView.getVisibility() != View.GONE)
{
itemView.setVisibility(View.GONE);
}
}
}
//准备完数据后开始动画
for (int i = 0; i < mVisibleView.size(); i++)
{
if (mVisibledView.contains(mVisibleView.get(i))) //本来就显示的做平移动画
{
ObjectAnimator
.ofFloat(mVisibleView.get(i), "translationX",
(mVisibleView.get(i).getmLastPosition() - mVisibleView.get(i).getmCurrentPosition()), 0f).setDuration(500).start();
} else//未显示的setVisibility(View.VISIBLE)
{
mVisibleView.get(i).setVisibility(View.VISIBLE);
AlphaAnimation mAlphaAnimation = new AlphaAnimation(0.0f, 1.0f);
mAlphaAnimation.setDuration(200);
mAlphaAnimation.setInterpolator(new AccelerateInterpolator());
mVisibleView.get(i).startAnimation(mAlphaAnimation);
}
}
}
}