最近有用到在GridView 中选择单个的Item 时,需要将选择的Item 放大的需求.就网上查找了一下相关资料,同时查看了一下android相关的源码.
这里记录一下,以便日后回忆和继续完善这个笔记.
首先我们要知道在上面描述的情况下,一个ViewGroup 会有几个child view.我们如果只是直接使用缩放动画去放大那个选中View 会发现一个问题:选中的view 放大之后会被parent 的其他child 遮挡.如果我们强行使用bringToFront(),就会发现顺序会被改变,而且还有其他问题出现.
其实在ViewGroup 绘制各个child 的时候是有一个顺序的,正常情况下就是按照GridView 各个child 从左到右,从上到下的顺序来绘制的.
当时这个顺序是可以改变的.
这其中涉及到2个ViewGroup关键方法:
protected int getChildDrawingOrder(int childCount, int i) {
return i;
}
protected void setChildrenDrawingOrderEnabled(boolean enabled) {
setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
}
如果要把选择的child View 放大,并显示在最上方不被其他view 遮挡.我们就需要修改绘制顺序.也就是重写getChildDrawingOrder()方法. 同时也要设置
setChildrenDrawingOrderEnabled(true); 来确保绘制时更新之后的顺序是有效的.
ViewGroup 的dispatchDraw方法(删除部分不需要看的代码了)
@Override
protected void dispatchDraw(Canvas canvas) {
boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
final int childrenCount = mChildrenCount;
final View[] children = mChildren;
int flags = mGroupFlags;
//.....
boolean more = false;
final long drawingTime = getDrawingTime();
if (usingRenderNodeProperties) canvas.insertReorderBarrier();
final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
int transientIndex = transientCount != 0 ? 0 : -1;
// Only use the preordered list if not HW accelerated, since the HW pipeline will do the
// draw reordering internally
final ArrayList<View> preorderedList = usingRenderNodeProperties
? null : buildOrderedChildList();
final boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
for (int i = 0; i < childrenCount; i++) {
while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
final View transientChild = mTransientViews.get(transientIndex);
if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
transientChild.getAnimation() != null) {
more |= drawChild(canvas, transientChild, drawingTime);
}
transientIndex++;
if (transientIndex >= transientCount) {
transientIndex = -1;
}
}
int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
final View child = (preorderedList == null)
? children[childIndex] : preorderedList.get(childIndex);
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
}
}
while (transientIndex >= 0) {
// there may be additional transient views after the normal views
final View transientChild = mTransientViews.get(transientIndex);
if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
transientChild.getAnimation() != null) {
more |= drawChild(canvas, transientChild, drawingTime);
}
transientIndex++;
if (transientIndex >= transientCount) {
break;
}
}
if (preorderedList != null) preorderedList.clear();
// Draw any disappearing views that have animations
if (mDisappearingChildren != null) {
final ArrayList<View> disappearingChildren = mDisappearingChildren;
final int disappearingCount = disappearingChildren.size() - 1;
// Go backwards -- we may delete as animations finish
for (int i = disappearingCount; i >= 0; i--) {
final View child = disappearingChildren.get(i);
more |= drawChild(canvas, child, drawingTime);
}
}
if (usingRenderNodeProperties) canvas.insertInorderBarrier();
//.....
}
从上面代码可以看到getChildDrawingOrder 和setChildrenDrawingOrderEnabled 的作用了.
ViewGroup 的buildOrderedChildList方法
/**
* Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
* sorted first by Z, then by child drawing order (if applicable). This list must be cleared
* after use to avoid leaking child Views.
*
* Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
* children.
*/
ArrayList<View> buildOrderedChildList() {
final int count = mChildrenCount;
if (count <= 1 || !hasChildWithZ()) return null;
if (mPreSortedChildren == null) {
mPreSortedChildren = new ArrayList<View>(count);
} else {
mPreSortedChildren.ensureCapacity(count);
}
final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
for (int i = 0; i < mChildrenCount; i++) {
// add next child (in child order) to end of list
int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i;
View nextChild = mChildren[childIndex];
float currentZ = nextChild.getZ();
// insert ahead of any Views with greater Z
int insertIndex = i;
while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
insertIndex--;
}
mPreSortedChildren.add(insertIndex, nextChild);
}
return mPreSortedChildren;
}
了解了基本的流程之后,下面贴一下一个简单的demo源码
public class MainActivity extends Activity {
private Integer[] mImages = { R.drawable.p1,R.drawable.p2, R.drawable.p3,
R.drawable.p4, R.drawable.p5,R.drawable.p6};
GridAdapter mImageAdapter;
private final String TAG = "zhangle";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyGridView gridview = (MyGridView) findViewById(R.id.gridview);
mImageAdapter = new GridAdapter(this, mImages);
gridview.setAdapter(mImageAdapter);
gridview.setSelector(new StateListDrawable());//不要选中时的背景效果
gridview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Log.d(TAG, "onItemClick position=" + position + " id=" +id);
gridview.setCurrentPosition(position);
setScaleAnimation(view);
}
});
}
private AnimationSet manimationSet;
public void setScaleAnimation(View view) {
AnimationSet animationSet = new AnimationSet(true);
if (manimationSet != null && manimationSet != animationSet) {
manimationSet.setFillAfter(false);
manimationSet.cancel();
}
// ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 2f, 1.0f,
// 2f, 1, 0.5f, 1, 0.5f);
Animation scaleAnimation = AnimationUtils.loadAnimation(this,
R.anim.anim);
animationSet.addAnimation(scaleAnimation);
animationSet.setFillAfter(true);
view.startAnimation(animationSet);
manimationSet = animationSet;
}
}
public class MyGridView extends GridView {
private final String TAG = "zhangle";
private int mCurrposition = 0;
public MyGridView(Context context) {
super(context);
}
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
setChildrenDrawingOrderEnabled(true);
}
public void setCurrentPosition(int pos) {
this.mCurrposition = pos;
}
@Override
protected void setChildrenDrawingOrderEnabled(boolean enabled) {
super.setChildrenDrawingOrderEnabled(enabled);
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
//把第一个和最后一个的绘制顺序交换一下
if (i == childCount - 1) {
return mCurrposition;
}
if (i == mCurrposition) {
return childCount - 1;
}
return super.getChildDrawingOrder(childCount, i);
}
}
public class GridAdapter extends BaseAdapter {
private final String TAG = "zhangle";
private Context mContext;
private int selected = -1;
private Integer[] list;
public GridAdapter(Context context, Integer[] list) {
this.mContext = context;
this.list = list;
}
@Override
public int getCount() {
return list.length;
}
@Override
public Object getItem(int position) {
return list[position];
}
@Override
public long getItemId(int position) {
return position;
}
public void setSelectPosition(int id) {
selected = id;
this.notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(300, 300));
imageView.setImageResource(list[position]);
imageView.setPadding(10, 10, 10, 10);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
// imageView.setBackgroundResource(R.drawable.grid_item_sele_style);
Log.d(TAG, "getView selected=" + selected + " position=" +position);
/*if (selected == position) {
setScaleAnimation(imageView);
}*/
return imageView;
}
}
以上就是主要的源码.
参考:http://blog.csdn.net/coderinchina/article/details/51344970