I want to create a custom view that will act as a container for other custom views. The user will be able to move the view you want to move by dragging it.
For the container, I implement it by extending ViewGroup
:
public class MyContainer extends ViewGroup {
public MyContainer(Context context) {
super(context);
init(context);
}
public MyContainer(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyContainer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
public void addItem(AbstractView view) {
addView(view);
}
}
For the custom view, I create an AbstractView
class and create two views RectView
and CircleView
by extending it:
abstract public class AbstractView extends View {
protected float mX, mY;
protected int mWidth, mHeight;
protected final Paint mShapePaint;
public AbstractView(Context context, float x, float y, int width, int height) {
super(context);
mShapePaint = new Paint();
mShapePaint.setColor(Color.BLACK);
mShapePaint.setStyle(Paint.Style.STROKE);
mX = x;
mY = y;
mWidth = width;
mHeight = height;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Measure the view
int width = resolveSize(mWidth, widthMeasureSpec);
int height = resolveSize(mHeight, heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
// Update the position of the item when it is moved
mX = event.getX();
mY = event.getY();
invalidate();
break;
}
return true;
}
}
public class CircleView extends AbstractView {
public CircleView(Context context, float x, float y) {
super(context, x, y, 100, 100);
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawCircle(mX, mY, mWidth/2f, mShapePaint);
}
}
public class RectView extends AbstractView {
public RectView(Context context, float x, float y) {
super(context, x, y, 100, 40);
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawRect(mX, mY, mX + mWidth, mY + mHeight, mShapePaint);
}
}
Here is the code for MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyContainer myContainer = findViewById(R.id.myContainer);
myContainer.addItem(new RectView(this, 50, 50));
myContainer.addItem(new CircleView(this, 200, 200));
}
}
Finally here is the xml file:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.my.package.name.MyContainer
android:id="@+id/myContainer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
When I run this code nothing visible on the screen, but when I extend FrameLayout
instead of ViewGroup
(as someone suggests) and remove onLayout
method from the code, the view is now visible but I can only drag the last added view to this groupView (only able to move the topmost View). My question is: how can I make the views visible and be able to move them? (I think the problem is because I need to implement onMesure
and onLayout
for the groupView but I don't know how to implement them in this case) or at least How can I move the other views (not just the top most view) in the case of extending FrameLayout
?