How to create a semi-transparent instruction page in Android?

前端 未结 4 1271
花落未央
花落未央 2021-01-30 02:55

I am new to Android and trying to work on this problem for last 2 days but could find a solution. Any help will be highly appreciated. How to create a semi-transparent page for

4条回答
  •  执念已碎
    2021-01-30 03:13

    I just implemented Ted's answer in one of my projects. Great! Extremely easy to implement and great looking result. Many thanks for this Ted.

    But as Stack Overflow is for taking and sharing I would like to share my implementation of a customized view that creates arrows in the form of a "needle" that I used with Ted's approach to make the original answer complete. Here is the code:

    package com.yourpackage;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PointF;
    import android.util.AttributeSet;
    import android.view.View;
    import de.nantoka.miep.R;
    
    public class CoachmarkArrow extends View {
    
        private static final float CIRCLE_RADIUS = 1.5f;
        private static final int TOPLEFT = 0;
        private static final int TOPRIGHT = 1;
        private static final int BOTTOMLEFT = 2;
        private static final int BOTTOMRIGHT = 3;
    
        Paint paint;
        int from, to;
    
        PointF padding = new PointF();
        PointF fromPoint = new PointF();
        PointF toPoint = new PointF();
    
        public CoachmarkArrow (Context context, AttributeSet attrs) {
            super(context, attrs);
    
            TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CoachmarkArrow, 0, 0);
    
            getPaint(a);
            getFromTo(a);
    
            a.recycle();
        }
    
        private void getFromTo(TypedArray a) {
    
            from = a.getInt(R.styleable.CoachmarkArrow_from, BOTTOMLEFT);
            to = a.getInt(R.styleable.CoachmarkArrow_to, TOPLEFT);
        }
    
        private void getPaint(TypedArray a) {
            paint = new Paint();
    
            paint.setColor(a.getColor(R.styleable.CoachmarkArrow_color, Color.WHITE));
            paint.setStrokeWidth(a.getDimensionPixelSize(R.styleable.CoachmarkArrow_size, 0));
    
            paint.setStrokeCap(Paint.Cap.BUTT);
            paint.setAntiAlias(true);
        }
    
        @Override
        protected void onDraw (Canvas canvas){
            calculatePadding(canvas);
            calculateLinePoints();
    
            drawLine(canvas, fromPoint, toPoint);
            drawCircle(canvas, fromPoint);
        }
    
        private void calculateLinePoints() {
            fromPoint = getPoint(from);
            toPoint = getPoint(to);
        }
    
        private void calculatePadding(Canvas canvas) {
    
            padding.x = CIRCLE_RADIUS * paint.getStrokeWidth() / canvas.getWidth();
            padding.y = CIRCLE_RADIUS * paint.getStrokeWidth() / canvas.getHeight();
        }
    
        private PointF getPoint(int position) {
            PointF point = new PointF();
    
            if (position == TOPRIGHT || position == BOTTOMRIGHT){
                point.x = 1.0f - padding.x;
            }
            else {
                point.x = padding.x;
            }
    
            if (position == BOTTOMLEFT || position == BOTTOMRIGHT){
                point.y = 1.0f - padding.y;
            }
            else {
                point.y = padding.y;
            }       
    
            return point;
        }
    
        private void drawCircle(Canvas canvas, PointF fromPoint) {
    
            canvas.drawCircle(
                    canvas.getWidth() * fromPoint.x, 
                    canvas.getHeight() * fromPoint.y, 
                    CIRCLE_RADIUS * paint.getStrokeWidth(), 
                    paint
                    );
        }
    
        private void drawLine(Canvas canvas, PointF fromPoint, PointF toPoint) {
            canvas.drawLine(
                    canvas.getWidth() * fromPoint.x, 
                    canvas.getHeight() * fromPoint.y, 
                    canvas.getWidth() * toPoint.x, 
                    canvas.getHeight() * toPoint.y, 
                    paint
                    );
        }
    }
    

    Add this class to your project (any package name is fine) and create an attribute file under res/values for the XML parameters:

    
    
        
            
            
            
                
                
                
                
            
            
                
                
                
                
            
        
    
    

    Now you can create the "needles" in the XML-Layout of your coachmarks activity like any other view, for example

      
    

    creates a "needle" that has the head at the bottom right and the tip at the top left corner of a rectangle that is 100 dp high and as wide as the containing parent ViewGroup.

    That way you can create coachmarks that adapt automatically to the different screen sizes. For example, if you use a relative layout, create a dummy view for the UI element you want to describe in your coachmarks activity, and tell the relative layout to put the coach mark below the dummy view but above the explanation text box that you center in the middle of the window. That way the coachmark gets automatically the right size to point from the text box to the UI element.

    Hope this helps somebody!

提交回复
热议问题