5

我正在研究扩展 ViewGroup 以安排 GridView 的视图项的类。

我可以通过以下方式轻松地在其中添加一个新的 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()

我还尝试将所有视图项存储在列表中,调用方法 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 分离,并在类中对其进行多次复制(复制)。

任何帮助表示赞赏。

4

3 回答 3

2

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

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

你得到的例外是ViewGroup 检查你View的父null级的结果 所以,为了添加克隆的视图,你必须将你的视图的mParent成员设置为null,你不能直接这样做,因为这样做的方法不是公共:View.assignParent()

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您就可以不用修改容器的行为。

于 2013-08-07T09:28:02.067 回答
1

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

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

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

于 2013-08-07T08:30:20.557 回答
1

感谢 SD 和 Ivan 的回答。

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

无法在 View 中直接添加 Clone 方法,添加接口使代码更加复杂。

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

必须做一些技巧来复制视图,首先获取另一个视图实例并复制第二个视图的可绘制、背景、填充等属性。

通过使用以下代码,解决方案要容易得多。

// 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);
于 2014-06-12T12:09:33.450 回答