版权声明:本文为博主原创文章,未经博主允许不得转载。 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