【达内课程】自定义控件(走势图)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010356768/article/details/89370762

控件选择顺序:原生,开源,自定义控件

今天做一个类似于股票走势图的控件,效果图:
在这里插入图片描述
首先先了解下自定义控件的执行流程

新建CustomView

CustomView

//继承View或View的子类,就是自定义控件
public class CustomView extends View {
    int viewHeight;
    int viewWidth;

    //AttributeSet对应布局中的属性
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //得到控件大小
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        viewWidth = w;
        viewHeight = h;
        super.onSizeChanged(w, h, oldw, oldh);
    }

    //canvas画文字,图形
    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(Color.BLACK);

        Rect rect = new Rect(0,0,viewWidth,viewHeight);
        canvas.drawRect(rect,paint);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

}

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

activity_main

<com.xx.myapplication.CustomView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

第一次执行流程
MainActivity中onCreate中的setContentView执行后
执行自定义控件的构造方法
onSizeChanged
onDraw
如果单击,触发onTouchEvent

如果横竖屏发生变化
会重新执行MainActivity的onCreate
执行自定义控件的构造方法
onSizeChanged
onDraw

如果AndroidManifest中设置configChanges

android:configChanges="orientation|screenSize|keyboardHidden"

再次执行程序,第一次执行流程还是相同的
如果横竖屏发生变化,会直接再次执行
onSizeChanged
onDraw

现在我们绘制底部的数字
在这里插入图片描述
CustomView

//继承View或View的子类,就是自定义控件
public class CustomView extends View {
    int viewHeight;
    int viewWidth;
    private ArrayList<HashMap<String, String>> list;
    int timeGap;//时间间隙

    public void setData(ArrayList<HashMap<String,String>> list){
        this.list = list;
    }

    //AttributeSet对应布局中的属性
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //得到控件大小
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        viewWidth = w;
        viewHeight = h;
        super.onSizeChanged(w, h, oldw, oldh);
    }

    //canvas画文字,图形
    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(Color.BLACK);

        Rect rect = new Rect(0,0,viewWidth,viewHeight);
        canvas.drawRect(rect,paint);

        //画时间
        paint.setColor(Color.WHITE);
        paint.setTextSize(24);
        //用代码得最后的时间文字的宽度
        String lastTime = list.get(list.size() - 1).get("time");
        Rect sizeRect = new Rect();
        //矩形大小就是文字的大小
        paint.getTextBounds(lastTime,0,lastTime.length(),sizeRect);
        int lastTimeWidth = sizeRect.width();
        timeGap = (viewWidth-lastTimeWidth)/(list.size()-1);

        for(int i=0;i<list.size();i++){
            HashMap<String,String> hashMap = list.get(i);
            String time = hashMap.get("time");
            int timeX = i*timeGap;
            //画文字的时候,y在文字的下面
            int timeY = viewHeight;
            canvas.drawText(time,timeX,timeY,paint);
        }

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

}

MainActivity

public class MainActivity extends AppCompatActivity {
    private CustomView customView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        customView = findViewById(R.id.customView);
        customView.setData(getData());
    }

    public ArrayList<HashMap<String,String>> getData(){
        ArrayList<HashMap<String,String>> list = new ArrayList<>();
        HashMap<String,String> map = new HashMap<>();
        map.put("time","9");
        map.put("price","3200");
        list.add(map);

        map = new HashMap<>();
        map.put("time","10");
        map.put("price","5000");
        list.add(map);

        map = new HashMap<>();
        map.put("time","11");
        map.put("price","8000");
        list.add(map);

        map = new HashMap<>();
        map.put("time","13");
        map.put("price","7800");
        list.add(map);

        return list;
    }
}

画价格

在这里插入图片描述

//继承View或View的子类,就是自定义控件
public class CustomView extends View {
	......
    int maxPrice;//最大价格

    public void setData(ArrayList<HashMap<String,String>> list){
        this.list = list;
        //计算最大价格
        for(int i=0;i<list.size();i++){
            int currentPrice = Integer.parseInt(list.get(i).get("price"));
            if(currentPrice > maxPrice){
                maxPrice = currentPrice;
            }
        }
    }

	......

    //canvas画文字,图形
    @Override
    protected void onDraw(Canvas canvas) {
       	.....
        //价格高度 = 视图高度 - 文字高度
        int priceHeight = viewHeight -sizeRect.height();

        timeGap = (viewWidth-lastTimeWidth)/(list.size()-1);

        for(int i=0;i<list.size();i++){
            HashMap<String,String> hashMap = list.get(i);
            String time = hashMap.get("time");
            int timeX = i*timeGap;
            //画文字的时候,y在文字的下面
            int timeY = viewHeight;
            canvas.drawText(time,timeX,timeY,paint);
            //画价格
            String price = hashMap.get("price");
            int currentPrice = Integer.parseInt(price);
            int priceY = currentPrice * priceHeight / maxPrice;
            //值越大,显示在下面。应该显示在上面
            priceY = priceHeight - priceY;
            //最大值 显示在控件外面
            priceY = priceY + sizeRect.height();
            canvas.drawText(price,timeX,priceY,paint);
        }

    }
......
}

画线

//继承View或View的子类,就是自定义控件
public class CustomView extends View {
    ......
    
    //canvas画文字,图形
    @Override
    protected void onDraw(Canvas canvas) {
        ......

        //画时间
        ......

        for(int i=0;i<list.size();i++){
            ......

            //画线
            if(i<list.size()-1){
                int startX=0,startY=0,stopX=0,stopY=0;
                startX = timeX;
                startY = priceY;
                stopX = (i+1)*timeGap;
                int nextPrice = Integer.parseInt(list.get(i+1).get("price"));
                stopY = nextPrice * priceHeight /maxPrice;
                //倒过来,大的应该显示在上面
                stopY = priceHeight-stopY;
                //最大的值可能跑到屏幕外,所以加上文字高度
                stopY = stopY + sizeRect.height();
                canvas.drawLine(startX,startY,stopX,stopY,paint);
            }
        }

    }

   ......

}

现在把价格改为随机变化的
在这里插入图片描述
修改MainActivity

public class MainActivity extends AppCompatActivity {
    private CustomView customView;
    Random random = new Random();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        customView = findViewById(R.id.customView);
        customView.setData(getData());

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                customView.setData(getData());
                //让android框架去调用ondraw、
                //间接调用
                customView.invalidate();
                handler.postDelayed(this,1000);
            }
        },1000);
    }

    public ArrayList<HashMap<String,String>> getData(){
        ArrayList<HashMap<String,String>> list = new ArrayList<>();
        HashMap<String,String> map = new HashMap<>();
        map.put("time","9");
        map.put("price",String.valueOf(random.nextInt(5000)));
        list.add(map);

        map = new HashMap<>();
        map.put("time","10");
        map.put("price",String.valueOf(random.nextInt(5000)));
        list.add(map);

        map = new HashMap<>();
        map.put("time","11");
        map.put("price",String.valueOf(random.nextInt(5000)));
        list.add(map);

        map = new HashMap<>();
        map.put("time","13");
        map.put("price",String.valueOf(random.nextInt(5000)));
        list.add(map);

        return list;
    }
}

现在增加点击画线功能
在这里插入图片描述

//继承View或View的子类,就是自定义控件
public class CustomView extends View {
   	......
    int touchY;//单击的Y坐标

  	......

    //canvas画文字,图形
    @Override
    protected void onDraw(Canvas canvas) {
        ......

        //画线
        if(touchY>0){
            paint.setColor(Color.RED);
            canvas.drawLine(0,touchY,viewWidth,touchY,paint);
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        touchY = (int) event.getY();
        int x = (int) event.getX();
        //单击的第几个时间点
        int index = x/timeGap;
        Toast.makeText(getContext(),"第"+index+"个,"+list.get(index).get("time"),Toast.LENGTH_SHORT).show();
        return super.onTouchEvent(event);
    }

}

注意:
绘制文本的时候,参数X,Y并不是绘制的起点,而是文字的底部,这个x,y 是文字的左下角的坐标

demo下载地址
https://download.csdn.net/download/u010356768/11131421

猜你喜欢

转载自blog.csdn.net/u010356768/article/details/89370762
今日推荐