Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Duplicating View element in the ViewGroup

I am working on class that extends ViewGroup to arrange the View items for the GridView.

I can easily add a new View item inside it by:

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

Or removing View item is also easy

removeViewAt(remove_index)

Swapping the item can be done by

addView(new_index, removeViewAt(old_index));

but I want to duplicate the View item when one item is dragged over the another one. I tried to duplicate the the item by

addView(getChildAt(index))

And this shows the exception error

The specified child already has a parent. You must call removeView() on the child's parent first

I also tried to store all the view items in the List, called the method removeAllView() and again added the views in class.

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));
}

This still shows the exception error as above:

The view inflating may work but I want to copy the same view without going for the external resource.

So I want the method to detach that View from parent ViewGroup and make multiple copy (Duplicate) of it inside the class.

Any help is appreciated.

like image 656
Hem Shrestha Avatar asked Oct 04 '22 07:10

Hem Shrestha


2 Answers

First, you're trying to add that same object again, which doesn't really make sense - the new view has to be a separate object, you'd have to duplicate the original first, e.g. using .clone() method.

But, unfortunately, even if you did, you couldn't add the cloned view to the ViewGroup, here's why.

The exception you get is the result of ViewGroup checking your View's parent for null So, in order to add the cloned view, you'd have to set your view's mParent member to null, which you can't do directly because the method that does that is not public: View.assignParent()

You could try to clone the View after you call .removeViewAt() so that it doesn't have a parent at the time of cloning, then add the original view back to it's position and then proceed with adding the clone to the required place, but as S.D. mentioned you'd have to have some hassle with cloning plus this way is very obscure and will require the ViewGroup to relayout 2 times.

A better solution is to assign a tag to each view that contains the necessary info to create another View like that and use it when you need to clone.

I would do something like this:

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);

For any additional view or group you'll want to use instead of the single ImageView thing just create another implementation of ViewCloner and you're good to go without having to modify your container's behaviour.

like image 159
Ivan Bartsov Avatar answered Oct 10 '22 01:10

Ivan Bartsov


Duplicating an object requires a good implementation of clone() method.

I don't think Android's view classes do this well, so you may need to create a custom type of view that can produce a copy of itself. View class does have methods to save/restore state: with onSaveInstanceState () and onRestoreInstanceState() which you can use to copy View's state.

Also, you will need to take care of event listeners registered on that view.

like image 31
S.D. Avatar answered Oct 10 '22 02:10

S.D.