Android使用自定义view实现标题栏、梯形布局以及二维码扫描

案例效果图:

Android使用自定义view实现标题栏、梯形布局以及二维码扫描_第1张图片Android使用自定义view实现标题栏、梯形布局以及二维码扫描_第2张图片Android使用自定义view实现标题栏、梯形布局以及二维码扫描_第3张图片



项目清单文件权限:





build.gradle添加依赖
compile 'com.journeyapps:zxing-android-embedded:3.3.0'



要求:

实现如图所示效果,标题栏通过组合View的方式进行实现,统一对外暴露左侧按钮和右侧按钮点击

的方法,在点击右侧的回调方法中跳转到图二所示页面,图二的页面标题栏显示上一个页面组合View

的视图,通过自定义ViewGroup的方式实现梯形布局(下一个视图的起始位置是上一个视图的结束位置)。

图一中间的进度条使用继承自View的方式进行实现,并使用自定义属性的方式来设置进度条中间的颜色。

点击扫描二维码按钮之后,进度条开始以每秒10%的进度进行,当进度条走到100%后,跳转到图三的扫

描二维码页面,实现扫描二维码的功能。

通过组合View的方式实现标题栏



header.xml




    

    

    

Header.java

package com.bwie.tixing;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;


public class Header extends RelativeLayout {
    private TextView mTextView;
    private ImageView ib_right;
    private ImageView ib_left;

    private String titleText;
    private int titleTextColor;
    private float titleTextSize;

    public Header(Context context) {
        super(context);
    }

    public Header(Context context, AttributeSet attrs) {
        super(context, attrs);

        //加载视图的布局
        LayoutInflater.from(context).inflate(R.layout.header,this,true);

        //加载自定义的属性
        TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.Header);
        titleText=a.getString(R.styleable.Header_titleText);
        titleTextColor=a.getColor(R.styleable.Header_titleTextColor, Color.WHITE);
        titleTextSize=a.getDimension(R.styleable.Header_titleTextSize,20f);

        //回收资源,这一句必须调用
        a.recycle();
    }

    /**
     * 此方法会在所有的控件都从xml文件中加载完成后调用
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        //获取子控件
        mTextView= (TextView) findViewById(R.id.tv_header);
        ib_right= (ImageView) findViewById(R.id.ib_right);
        ib_left = findViewById(R.id.ib_left);
        //将从资源文件中加载的属性设置给子控件
        if (!TextUtils.isEmpty(titleText))
            setPageTitleText(titleText);
        setPageTitleTextColor(titleTextColor);
        setPageTitleTextSize(titleTextSize);

    }

    /**
     * 设置标题文字
     * @param text
     */
    public void setPageTitleText(String text) {
        mTextView.setText(text);
    }

    /**
     * 设置标题文字颜色
     * @param color
     */
    public void setPageTitleTextColor(int color) {
        mTextView.setTextColor(color);
    }

    /**
     * 设置标题文字大小
     * @param size
     */
    public void setPageTitleTextSize(float size) {
        mTextView.setTextSize(size);
    }

    /**
     * 设置按钮点击事件监听器
     * @param listener
     */
    public void setOnRightClickListener(OnClickListener listener) {
        ib_right.setOnClickListener(listener);
    }

    public void setOnLeftClickListener(OnClickListener listener) {
        ib_left.setOnClickListener(listener);
    }
}

通过自定义属性实现进度条

attrs.xml




    
        
        
        
        
        
        

        
        
        
    
    
        
        
        
    

PxUtils.java

package com.bwie.tixing;

import android.content.Context;
import android.util.TypedValue;


public class PxUtils {


    public static int dpToPx(int dp, Context context) {

        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());

    }


    public static int spToPx(int sp, Context context) {

        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());

    }


}

CirclePercentView.java

package com.bwie.tixing;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;


public class CirclePercentView extends View {


    //圆的半径
    private float mRadius;

    //色带的宽度
    private float mStripeWidth;
    //总体大小
    private int mHeight;
    private int mWidth;

    //动画位置百分比进度
    private int mCurPercent;

    //实际百分比进度
    private int mPercent;
    //圆心坐标
    private float x;
    private float y;

    //要画的弧度
    private int mEndAngle;

    //小圆的颜色
    private int mSmallColor;
    //大圆颜色
    private int mBigColor;

    //中心百分比文字大小
    private float mCenterTextSize;

    public CirclePercentView(Context context) {
        this(context, null);
    }

    public CirclePercentView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CirclePercentView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePercentView, defStyleAttr, 0);
        mStripeWidth = a.getDimension(R.styleable.CirclePercentView_stripeWidth, PxUtils.dpToPx(30, context));
        mCurPercent = a.getInteger(R.styleable.CirclePercentView_percent, 0);
        mSmallColor = a.getColor(R.styleable.CirclePercentView_smallColor,0xffafb4db);
        mBigColor = a.getColor(R.styleable.CirclePercentView_bigColor,0xff6950a1);
        mCenterTextSize = a.getDimensionPixelSize(R.styleable.CirclePercentView_centerTextSize,PxUtils.spToPx(20,context));
        mRadius = a.getDimensionPixelSize(R.styleable.CirclePercentView_radius,PxUtils.dpToPx(100,context));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取测量模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //获取测量大小
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
            mRadius = widthSize / 2;
            x = widthSize / 2;
            y = heightSize / 2;
            mWidth = widthSize;
            mHeight = heightSize;
        }

        if(widthMode == MeasureSpec.AT_MOST&&heightMode ==MeasureSpec.AT_MOST){
            mWidth = (int) (mRadius*2);
            mHeight = (int) (mRadius*2);
            x = mRadius;
            y = mRadius;

        }

        setMeasuredDimension(mWidth,mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {


        mEndAngle = (int) (mCurPercent * 3.6);
        //绘制大圆
        Paint bigCirclePaint = new Paint();
        bigCirclePaint.setAntiAlias(true);
        bigCirclePaint.setColor(mBigColor);


        canvas.drawCircle(x, y, mRadius, bigCirclePaint);


        //饼状图
        Paint sectorPaint = new Paint();
        sectorPaint.setColor(mSmallColor);
        sectorPaint.setAntiAlias(true);
        RectF rect = new RectF(0, 0, mWidth, mHeight);

        canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);


        //绘制小圆,颜色透明
        Paint smallCirclePaint = new Paint();
        smallCirclePaint.setAntiAlias(true);
        smallCirclePaint.setColor(mBigColor);
        canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint);


        //绘制文本
        Paint textPaint = new Paint();
        String text = mCurPercent + "%";

        textPaint.setTextSize(mCenterTextSize);
        float textLength = textPaint.measureText(text);

        textPaint.setColor(Color.WHITE);
        canvas.drawText(text, x - textLength/2, y, textPaint);

    }

    //外部设置百分比数
    public void setPercent(int percent) {
        if (percent > 100) {
            throw new IllegalArgumentException("percent must less than 100!");
        }

        setCurPercent(percent);


    }

    //内部设置百分比 用于动画效果
    private void setCurPercent(int percent) {




        mCurPercent = percent;
        CirclePercentView.this.postInvalidate();




    }

}

自定义ViewGroup的方式实现梯形布局

MyViewGroup.java

package com.bwie.tixing;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;


public class MyViewGroup extends ViewGroup {
    public MyViewGroup(Context context) {
        super(context);
    }

    public MyViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        int count = getChildCount();
        int startWidth = 0;
        int startHeight = 0;
        for (int l = 0; l < count; l++) {
            View v = getChildAt(l);
            v.layout(startWidth, startHeight, startWidth + v.getMeasuredWidth(), startHeight + v.getMeasuredHeight());
            startWidth += v.getMeasuredWidth();
            startHeight += v.getMeasuredHeight();
        }
    }
}

实现二维码扫描

自定义zxing二维码扫描页面
CustomViewfinderView.java
package com.bwie.tixing;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;

import com.google.zxing.ResultPoint;
import com.journeyapps.barcodescanner.ViewfinderView;

import java.util.ArrayList;
import java.util.List;


public class CustomViewfinderView extends ViewfinderView {
    public int laserLinePosition=0;
    public float[] position=new float[]{0f,0.5f,1f};
    public int[] colors=new int[]{0x00ffffff,0xffffffff,0x00ffffff};
    public LinearGradient linearGradient ;
    public CustomViewfinderView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }




    /**
     * 重写draw方法绘制自己的扫描框
     * @param canvas
     */
    @Override
    public void onDraw(Canvas canvas) {
        refreshSizes();
        if (framingRect == null || previewFramingRect == null) {
            return;
        }


        Rect frame = framingRect;
        Rect previewFrame = previewFramingRect;


        int width = canvas.getWidth();
        int height = canvas.getHeight();
        //绘制4个角


        paint.setColor(0xFFFFFFFF);//定义画笔的颜色
        canvas.drawRect(frame.left, frame.top, frame.left+70, frame.top+10, paint);
        canvas.drawRect(frame.left, frame.top, frame.left + 10, frame.top + 70, paint);


        canvas.drawRect(frame.right-70, frame.top, frame.right, frame.top+10, paint);
        canvas.drawRect(frame.right-10, frame.top, frame.right, frame.top+70, paint);


        canvas.drawRect(frame.left, frame.bottom-10, frame.left+70, frame.bottom, paint);
        canvas.drawRect(frame.left, frame.bottom-70, frame.left+10, frame.bottom, paint);


        canvas.drawRect(frame.right-70, frame.bottom-10, frame.right, frame.bottom, paint);
        canvas.drawRect(frame.right-10, frame.bottom-70, frame.right, frame.bottom, paint);
        // Draw the exterior (i.e. outside the framing rect) darkened
        paint.setColor(resultBitmap != null ? resultColor : maskColor);
        canvas.drawRect(0, 0, width, frame.top, paint);
        canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
        canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
        canvas.drawRect(0, frame.bottom + 1, width, height, paint);


        if (resultBitmap != null) {
            // Draw the opaque result bitmap over the scanning rectangle
            paint.setAlpha(CURRENT_POINT_OPACITY);
            canvas.drawBitmap(resultBitmap, null, frame, paint);
        } else {
            //  paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
            //  scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
            int middle = frame.height() / 2 + frame.top;
            laserLinePosition=laserLinePosition+5;
            if(laserLinePosition>frame.height())
            {
                laserLinePosition=0;
            }
            linearGradient= new LinearGradient(frame.left + 1, frame.top+laserLinePosition , frame.right -1 , frame.top +10+laserLinePosition, colors, position, Shader.TileMode.CLAMP);
            // Draw a red "laser scanner" line through the middle to show decoding is active


            //  paint.setColor(laserColor);
            paint.setShader(linearGradient);
            //绘制扫描线
            canvas.drawRect(frame.left + 1, frame.top+laserLinePosition , frame.right -1 , frame.top +10+laserLinePosition, paint);
            paint.setShader(null);
            float scaleX = frame.width() / (float) previewFrame.width();
            float scaleY = frame.height() / (float) previewFrame.height();


            List currentPossible = possibleResultPoints;
            List currentLast = lastPossibleResultPoints;
            int frameLeft = frame.left;
            int frameTop = frame.top;
            if (currentPossible.isEmpty()) {
                lastPossibleResultPoints = null;
            } else {
                possibleResultPoints = new ArrayList<>(5);
                lastPossibleResultPoints = currentPossible;
                paint.setAlpha(CURRENT_POINT_OPACITY);
                paint.setColor(resultPointColor);
                for (ResultPoint point : currentPossible) {
                    canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
                            frameTop + (int) (point.getY() * scaleY),
                            POINT_SIZE, paint);
                }
            }
            if (currentLast != null) {
                paint.setAlpha(CURRENT_POINT_OPACITY / 2);
                paint.setColor(resultPointColor);
                float radius = POINT_SIZE / 2.0f;
                for (ResultPoint point : currentLast) {
                    canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
                            frameTop + (int) (point.getY() * scaleY),
                            radius, paint);
                }
            }
            postInvalidateDelayed(16,
                    frame.left ,
                    frame.top ,
                    frame.right ,
                    frame.bottom);
            // postInvalidate();


        }
    }
}

CustomScanAct.java

package com.bwie.tixing;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.journeyapps.barcodescanner.CaptureManager;
import com.journeyapps.barcodescanner.DecoratedBarcodeView;


public class CustomScanAct extends Activity implements DecoratedBarcodeView.TorchListener { // 实现相关接口
    // 添加一个按钮用来控制闪光灯,同时添加两个按钮表示其他功能,先用Toast表示
    Button swichLight;
    DecoratedBarcodeView mDBV;
    private CaptureManager captureManager;
    private boolean isLightOn = false;




    @Override
    protected void onPause() {
        super.onPause();
        captureManager.onPause();
    }


    @Override
    protected void onResume() {
        super.onResume();
        captureManager.onResume();
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        captureManager.onDestroy();
    }


    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        captureManager.onSaveInstanceState(outState);
    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        return mDBV.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_customscan);
        swichLight = (Button) findViewById(R.id.btn_switch);
        mDBV= (DecoratedBarcodeView) findViewById(R.id.dbv_custom);


        mDBV.setTorchListener(this);


        // 如果没有闪光灯功能,就去掉相关按钮
        if (!hasFlash()) {
            swichLight.setVisibility(View.GONE);
        }
        //重要代码,初始化捕获
        captureManager = new CaptureManager(this, mDBV);
        captureManager.initializeFromIntent(getIntent(), savedInstanceState);
        captureManager.decode();
        //选择闪关灯
        swichLight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isLightOn) {
                    mDBV.setTorchOff();
                } else {
                    mDBV.setTorchOn();
                }
            }
        });
    }

    // torch 手电筒
    @Override
    public void onTorchOn() {
        Toast.makeText(this, "torch on", Toast.LENGTH_LONG).show();
        isLightOn = true;
    }


    @Override
    public void onTorchOff() {
        Toast.makeText(this, "torch off", Toast.LENGTH_LONG).show();
        isLightOn = false;
    }

    // 判断是否有闪光灯功能
    private boolean hasFlash() {
        return getApplicationContext().getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
    }

}

act_customscan.xml




    

MainActivity.java

package com.bwie.tixing;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;

public class MainActivity extends AppCompatActivity {
    private int count = 0;
    private CirclePercentView circlePercentView;
    private Header header;
    private TextView tvResult;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (count<100){
                count+=10;
                circlePercentView.setPercent(count);
                handler.sendEmptyMessageDelayed(0,1000);
            }else {
                Intent intent = new Intent(MainActivity.this, CustomScanAct.class);
                startActivity(intent);
                initEvent();
            }


        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        header = (Header) findViewById(R.id.header);
        circlePercentView = (CirclePercentView) findViewById(R.id.circleView);
        Button button = (Button) findViewById(R.id.button);
        tvResult = (TextView) findViewById(R.id.tvResult);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                handler.sendEmptyMessageDelayed(0,1000);
            }
        });

        header.setOnRightClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this,Main2Activity.class);
                startActivity(intent);
            }
        });



    }



    private void initEvent() {

        //假如你要用的是fragment进行界面的跳转
        //IntentIntegrator intentIntegrator = IntentIntegrator.forSupportFragment(ShopFragment.this).setCaptureActivity(CustomScanAct.class);
        IntentIntegrator intentIntegrator = new IntentIntegrator(MainActivity.this);
        intentIntegrator
                .setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES)
                .setPrompt("将二维码/条码放入框内,即可自动扫描")//写那句提示的话
                .setOrientationLocked(false)//扫描方向固定
                .setCaptureActivity(CustomScanAct.class) // 设置自定义的activity是CustomActivity
                .initiateScan(); // 初始化扫描
    }


    //获取扫描的结果
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        IntentResult intentResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
        if (intentResult != null) {
            if (intentResult.getContents() == null) {


            } else {
                // ScanResult 为获取到的字符串
                String ScanResult = intentResult.getContents();
                Log.d("zzz", "onActivityResult: "+ScanResult);
                tvResult.setText(ScanResult);
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
}

activity_main.xml




    

    

    

Main2Activity.java

package com.bwie.tixing;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;


public class Main2Activity extends AppCompatActivity {

    private Header header;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        header = (Header) findViewById(R.id.header);
        header.setOnLeftClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }
}

activity_main2.xml




    

    

        

        

        
    



你可能感兴趣的:(Android使用自定义view实现标题栏、梯形布局以及二维码扫描)