Android:在ViewGroup中复制View元素

时间:2013-08-07 08:12:22

标签: android android-view

我正在研究扩展ViewGroup的类,以安排GridView的View项目。

我可以通过以下方式轻松添加新的View项目:

ImageView view = new ImageView(context);
view.setImageBitmap(BitmapFactory.decodeResource( getResources(), R.drawable.ic_launcher));
addView(view);

或删除查看项目也很容易

removeViewAt(remove_index)

交换项目可以通过

完成
addView(new_index, removeViewAt(old_index));

但我希望在将一个项目拖过另一个项目时复制View项目。 我试图通过

复制该项目
addView(getChildAt(index))

这显示异常错误

  

指定的孩子已经有父母。您必须首先在孩子的父母上调用removeView()

我还尝试将所有视图项存储在List中,称为方法removeAllView()并再次在类中添加视图。

ArrayList<View> children = new ArrayList<View>();
for (int i = 0; i < getChildCount(); i++){
 children.add(getChildAt(i));
}            
children.add(getChildAt(index));          // duplicate this item
removeAllViews();

for (int i = 0; i < children.size(); i++){
 addView(children.get(i));
}

这仍然显示如上所述的异常错误:

视图膨胀可能有效但我想复制相同的视图而不需要外部资源。

所以我想让方法从父ViewGroup中分离出View,并在类中复制(复制)它。

感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

首先,你试图再次添加同一个对象,这实际上没有意义 - 新视图必须是一个单独的对象,你必须首先复制原始对象,例如使用.clone()方法。

但是,不幸的是,即使您这样做了,也无法将克隆视图添加到ViewGroup,这就是原因。

您获得的例外情况是ViewGroup checking your View's parent for null的结果 因此,为了添加克隆视图,您必须将视图的mParent成员设置为null,这是您无法直接执行的,因为执行此操作的方法不公开:{{ 3}}

您可以尝试在调用View后克隆.removeViewAt(),以便在克隆时没有父级,然后将原始视图添加回其位置,然后继续将克隆添加到所需位置,但作为SD提到你必须有一些克隆的麻烦加上这种方式非常模糊,需要ViewGroup重新布局2次。

更好的解决方案是为每个视图分配一个标记,其中包含创建另一个视图所需的信息,并在需要克隆时使用它。

我会做这样的事情:

public interface ViewCloner {
    public View clone(Context context);
}

public static class ImageViewCloner implements ViewCloner {
    private int mImgResId;
    public ImageViewCloner(int imgResourceId) {
        this.mImgResId = imgResourceId;
    }
    @override
    public View clone(Context context) {
        ImageView view = new ImageView(context);
        view.setImageBitmap(BitmapFactory.decodeResource( context.getResources(), mImgResId));
        // Add the tag to the clone as well, so it, too, can be cloned
        view.setTag(new ImageViewCloner(mImgResId));
        return view;
    }
}

// When creating the original view
int resId = R.drawable.ic_launcher;
ImageView view = new ImageView(context);
view.setImageBitmap(BitmapFactory.decodeResource( getResources(), resId));
view.setTag(new ImageViewCloner(resId));

// When cloning the view
ViewCloner vc = (ViewCloner) getChildAt(index).getTag();
View clone = vc.clone(getContext());
addView(clone);

对于您要使用的任何其他视图或组而不是单个ImageView,只需创建ViewCloner的另一个实现,您就可以不必修改容器的行为。

答案 1 :(得分:1)

复制对象需要良好实现clone()方法。

我不认为Android的视图类做得很好,因此您可能需要创建一个可以生成自身副本的自定义视图类型。 View类确实有保存/恢复状态的方法:使用onSaveInstanceState ()onRestoreInstanceState()可以用来复制View的状态。

此外,您需要处理在该视图上注册的事件侦听器。

答案 2 :(得分:1)

感谢S.D和Ivan的答案。

经过漫长的休息后,我可以找到自己的答案,将这些解决方案记在心里。

直接无法在视图中添加Clone方法,添加界面会使代码更加复杂。

甚至我的要求是克隆动态添加图像且源未知的视图。

必须完成一些技巧才能复制视图, 首先得到另一个视图实例,并在第二个上复制属性,如drawable,background,padding等。

使用以下代码可以更轻松地解决问题。

// Create new Instance of imageView
ImageView view = new ImageView(context);
// Get the original view
ImageView org = (ImageView)getChildAt(index);
// Copy drawable of that image
view.setImageDrawable(org.getDrawable());
// Copy Background of that image
view.setBackground(org.getBackground());
// Copy other required properties
....
// Lastly add that view
addView(view);