自定义圆形视图。放置意见

时间:2014-11-08 15:31:14

标签: android android-layout geometry

昨天我试图创建一个所有元素的自定义视图 像按钮,图像按钮,...围绕一个圆圈放置 等间距。

我的目标是得到这个:

enter image description here

我试过这段代码:

public class CircleView extends RelativeLayout {
    private OnDrop onDrop = null;
    private int radius = -1;
    private double step = -1;
    private double angle = -1;
    private static final int CENTER_ID = 111;

    public CircleView(Context context, OnDrop onDrop, int radius, List<View> elements) {
        super(context);

        this.onDrop = onDrop;
        this.radius = radius;
        this.step = (2 * Math.PI) / elements.size();

        RelativeLayout.LayoutParams layoutParamsView = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);

        this.setLayoutParams(layoutParamsView);
        this.addView(this.createCenter(context));

        for(View view : elements) {
            this.addView(this.placeView(view));
        }
    }

    private View placeView(View view) {
        RelativeLayout.LayoutParams layoutParams = createNewRelativeLayoutParams();

        int x = (int)(view.getWidth() / 2 + this.radius * Math.cos(this.angle));
        int y = (int)(view.getHeight() / 2 + this.radius * Math.sin(this.angle));

        this.angle += this.step;

        layoutParams.setMargins(x, 0, 0, y);
        view.setLayoutParams(layoutParams);

        return view;
    }

    private View createCenter(Context context) {
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(Globals.DRAG_TARGET_SIZE, Globals.DRAG_TARGET_SIZE);
        layoutParams.addRule(CENTER_HORIZONTAL);
        layoutParams.addRule(CENTER_VERTICAL);

        Button button = new Button(context);
        button.setId(CENTER_ID);
        button.setLayoutParams(layoutParams);

        return button;
    }

    private RelativeLayout.LayoutParams createNewRelativeLayoutParams() {
        RelativeLayout.LayoutParams layoutParameters = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        layoutParameters.addRule(RelativeLayout.ABOVE, CENTER_ID);
        layoutParameters.addRule(RIGHT_OF, CENTER_ID);

        return layoutParameters;
    }
}

我从这段代码得到的是:

enter image description here

这意味着创建具有相等间距的圆 元素工作得很好。但仍有问题 放置。 x和y坐标有问题。

有人可以帮我弄清楚如何纠正这种偏移吗?

1 个答案:

答案 0 :(得分:1)

我实现了自己的布局,将按钮循环放置在中心点周围:

/**
 *
 */
public class MenuCircularLayout extends MenuDragableButtonsLayout {
    /**
     * 
     */
    private RelativeLayout relativeLayoutCenter = null;
    /**
     * 
     */
    private List<View> menuButtons = null;
    /**
     * 
     */
    private ImageButton imageButtonCenter = null;
    /**
     * 
     */
    private int radius = -1;
    /**
     * 
     */
    private double step = -1;
    /**
     * 
     */
    private double angle = -1;
    /**
     * 
     */
    private static final int CENTER_ID = View.generateViewId();

    /**
     * 
     * @param context
     * @param callbackDrag
     * @param menuButtons
     */
    public MenuCircularLayout(Context context, CallbackDrag callbackDrag, List<View> menuButtons) {
        super(context);

        this.callbackDrag = callbackDrag;
        this.menuButtons = menuButtons;
        this.radius = Sizes.getDpToPx(context, Sizes.MENU_ICON_RADIUS);
        this.step = (2 * Math.PI) / menuButtons.size();

        this.initView();
    }

    /**
     * 
     */
    private void initView() {
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);

        this.setLayoutParams(layoutParams);

        RelativeLayout.LayoutParams layoutParamsCenter = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, Sizes.getOptimalMenuHeight(this.getContext()));
        layoutParamsCenter.addRule(RelativeLayout.CENTER_IN_PARENT);

        this.relativeLayoutCenter = new RelativeLayout(this.getContext());
        this.relativeLayoutCenter.setLayoutParams(layoutParamsCenter);
        this.relativeLayoutCenter.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);

        RelativeLayout.LayoutParams layoutParamsImageButtonCenter = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        layoutParamsImageButtonCenter.addRule(RelativeLayout.CENTER_IN_PARENT);

        this.imageButtonCenter = new ImageButton(this.getContext());
        this.imageButtonCenter.setId(CENTER_ID);
        this.imageButtonCenter.setLayoutParams(layoutParamsImageButtonCenter);
        this.imageButtonCenter.setImageDrawable(Images.loadDrawableFromFile(this.getContext(), Paths.IMAGE_POWER));
        this.imageButtonCenter.setBackground(null);
        this.imageButtonCenter.setOnDragListener(new DropTargetOnDragListener());
        this.imageButtonCenter.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);

        this.relativeLayoutCenter.addView(imageViewCenter);
        this.relativeLayoutCenter.addView(this.imageButtonCenter);
        this.relativeLayoutCenter.setOnDragListener(new MenuButtonOnDragListener());

        for(View view : this.menuButtons) {
            this.relativeLayoutCenter.addView(this.placeView(view));
        }

        this.addView(this.relativeLayoutCenter);
    }

    /**
     * 
     * @param view
     * @return
     */
    private View placeView(View view) {
        view.measure(0, 0);

        this.imageButtonCenter.measure(0, 0);

        int x = (int)((view.getMeasuredWidth() / 2) + this.radius * Math.cos(this.angle));
        int y = (int)((view.getMeasuredHeight() / 2) + this.radius * Math.sin(this.angle));

        this.angle += this.step;

        int deltaX = view.getMeasuredWidth();
        int deltaY = view.getMeasuredHeight();
        int deltaImageX = this.imageButtonCenter.getMeasuredWidth() / 2;
        int deltaImageY = this.imageButtonCenter.getMeasuredHeight() / 2;
        int xToDraw = ((x - deltaX) - deltaImageX);
        int yToDraw = ((y - deltaY) - deltaImageY);

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        layoutParams.addRule(RelativeLayout.ABOVE, CENTER_ID);
        layoutParams.addRule(RelativeLayout.RIGHT_OF, CENTER_ID);
        layoutParams.setMargins(xToDraw, 0, 0, yToDraw);

        view.setLayoutParams(layoutParams);
        view.setOnTouchListener(this);

        return view;
    }

    /**
     * 
     */
    @Override
    public void removeAllViews() {
        super.removeAllViews();

        this.relativeLayoutCenter.removeAllViews();
    }
}


/**
 * 
 */
public abstract class MenuDragableButtonsLayout extends RelativeLayout implements OnTouchListener {
    /**
     * 
     */
    protected CallbackDrag callbackDrag = null;

    /**
     * 
     * @param context
     */
    public MenuDragableButtonsLayout(Context context) {
        super(context);
    }

    /**
     * 
     */
    @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);

            view.startDrag(null, shadowBuilder, view, 0);
            view.setVisibility(View.INVISIBLE);
        } break;
        case MotionEvent.ACTION_UP: {
            view.performClick();
            view.setVisibility(View.VISIBLE);
        } break;
        }

        return true;
    }

    /**
     * 
     */
    public class MenuButtonOnDragListener implements OnDragListener {
        /**
         * 
         */
        @Override
        public boolean onDrag(View view, DragEvent event) {
            View sourceView = (View) event.getLocalState();

            float sourceX = sourceView.getX();
            float sourceY = sourceView.getY();
            float dropX = event.getX() - (sourceView.getWidth() / 2);
            float dropY = event.getY() - (sourceView.getHeight() / 2);

            switch(event.getAction()) {
                case DragEvent.ACTION_DRAG_EXITED : {
                    TranslateAnimation animation = new TranslateAnimation(dropX - sourceX, 0, dropY - sourceY, 0);
                    animation.setDuration(300);

                    sourceView.startAnimation(animation);
                    sourceView.setX(sourceX);
                    sourceView.setY(sourceY);
                    sourceView.setVisibility(View.VISIBLE);
                } break;
                case DragEvent.ACTION_DROP : {
                    sourceView.setX(dropX);
                    sourceView.setY(dropY);
                    sourceView.setVisibility(View.VISIBLE);

                    TranslateAnimation animation = new TranslateAnimation(dropX - sourceX, 0, dropY - sourceY, 0);
                    animation.setDuration(300);

                    sourceView.startAnimation(animation);
                    sourceView.setX(sourceX);
                    sourceView.setY(sourceY);
                } break;
            }

            return true;
        }
    }

    /**
     * 
     */
    public class DropTargetOnDragListener implements OnDragListener {
        /**
         * 
         */
        @Override
        public boolean onDrag(View view, DragEvent event) {
            switch(event.getAction()) {
            case DragEvent.ACTION_DROP :
                return callbackDrag.onDragCompleted(view, event);
            default :
                return true;
            }
        }
    }
}

/**
 * 
 */
public interface CallbackDrag {
    /**
     * 
     * @param view
     * @param event
     * @return
     */
    boolean onDragCompleted(final View view, final DragEvent event);
}

使用它像:

public class AnyClass implements CallbackDrag {

    private MenuCircularLayout circleView = null;

    /**
     * 
     */
    private void initMenu() {
        String email = this.getEmail();
        Map<String, Boolean> config = this.preferencesSettings.getSettings(email);

        List<View> views = new ArrayList<View>();
        views.add(this.buttonProfile);
        views.add(this.buttonMeasure);

        if(this.circleView != null) {
            this.circleView.removeAllViews();
            this.layoutMenu.removeView(this.circleView);

            this.circleView = null;
        }

        this.circleView = new MenuCircularLayout(this.getActivity(), this, views);
        this.circleView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
        this.layoutMenu.addView(this.circleView);
    }

    /**
     * 
     */
    @Override
    public boolean onDragCompleted(View view, DragEvent event) {
        View sourceView = (View) event.getLocalState();

        sourceView.setVisibility(View.VISIBLE);

        if(sourceView.equals(this.buttonMeasure)) {
            this.performNFCResult();
        } else if(sourceView.equals(this.buttonProfile)) {
            this.performProfile();
        }

        return true;
    }
}