自定义组件之【柱状图】详解 已封装成View
这是我以前在eoeandroid发的一个帖子,现在贴在我的博客中。
先上图,里面的数据时伪数据,用的时候传入参数即可。柱状图会根据数值的大小来变换显示的颜色,比如绿色、土黄色和红色。柱状图升高采用了类似于动画效果,可以在创建时设置是否启动动画效果。这个柱状图实现很简单,已经封装成一个view,大家可以直接使用,有什么问题和意见欢迎大家指教。
ConfigurationView 柱状图组件
package org.gmy.view.config; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.TextView; public class ConfigurationView extends View { private Paint paint; private Paint font_Paint; // 数值显示的偏移量 private int numWidth = 9; // 起始高度为 最大高度减去 80 【注意这里的高度是反的,也就是说,y轴是逐渐减少的】 private float startHeight = Configuration.HEIGHT-80; private float endHeight = startHeight; // 柱状图的宽度 private int viewWidth = 20; // 组态图的高度 【显示的数值,100 为 100%】 private int maxSize = 43; private int indexSize = 0; // 要显示的模式 【类型,比如:℃和百分比等】 private String displayMode = "%"; // 模式 private boolean mode = false; // 线程控制 private boolean display = true; // 是否开启动画效果 private boolean animMode = true; /** * * @param context * @param maxSize 需要显示的数值 * @param displayMode 显示的类型 */ public ConfigurationView(Context context, int maxSize, String displayMode) { super(context); this.maxSize = maxSize; this.displayMode = displayMode; init(); } /** * * @param context * @param maxSize 需要显示的数值 * @param displayMode 显示的类型 * @param mode 显示的模式,默认为false,数值越高,颜色越偏向红色。为true反之 */ public ConfigurationView(Context context, int maxSize, String displayMode, boolean mode) { super(context); this.maxSize = maxSize; this.displayMode = displayMode; this.mode = mode; init(); } /** * * @param context * @param maxSize 需要显示的数值 * @param displayMode 显示的类型 * @param mode 显示的模式,默认为false,数值越高,颜色越偏向红色。为true反之 * @param animMode 是否显示动画加载效果,默认为true */ public ConfigurationView(Context context, int maxSize, String displayMode, boolean mode, boolean animMode) { super(context); this.maxSize = maxSize; this.displayMode = displayMode; this.mode = mode; this.animMode = animMode; init(); } // 绘制界面 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(10, endHeight, 10+viewWidth, startHeight, paint); if(!display){ // 这段if语句可以放在初始化中,这个就交给大家吧。 if(!mode && indexSize >= 50){ paint.setARGB(255, 200, 200, 60); if(!mode && indexSize >= 80){ paint.setARGB(255, (indexSize<100)?(110+indexSize+45):255, (indexSize<100)?210-(indexSize+45):0, 20); } }else if(mode && indexSize <= 50){ paint.setARGB(255, 200, 200, 60); if(mode && indexSize <= 30){ paint.setARGB(255, 255-indexSize, indexSize, 20); } } canvas.drawRect(10, endHeight, 10+viewWidth, startHeight, paint); paint.setARGB(255, 99, 66, 0); canvas.drawText(""+indexSize, numWidth, endHeight-5, paint); paint.setARGB(255, 110, 210, 60); } canvas.drawText(displayMode, 0, startHeight+15, font_Paint); } // 初始化 private void init(){ // 数值初始化 paint = new Paint(); paint.setARGB(255, 110, 210, 20); font_Paint = new Paint(); font_Paint.setARGB(255, 66, 66, 66); // 设置顶端数值显示的偏移量,数值越小,偏移量越大 numWidth = 9; if(maxSize < 10){ numWidth = 15; }else if(maxSize < 100){ numWidth = 12; } if(animMode){ // 启动一个线程来实现柱状图缓慢增高 thread.start(); }else{ // 不启用动画效果,则直接赋值进行绘制 display = false; indexSize = maxSize; endHeight = startHeight-(float) (maxSize*1.5); invalidate(); } } private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 通过endHeight >= 20将柱状图的高度控制在150以内,这样刚好循环一百次到顶部 if(msg.what == 1 && indexSize < maxSize && endHeight >= 20){ endHeight -= 1.5; indexSize += 1; }else{ display = false; } invalidate(); } }; private Thread thread = new Thread(){ @Override public void run(){ while(!Thread.currentThread().isInterrupted() && display ) { Message msg = new Message(); msg.what = 1; handler.sendMessage(msg); try { // 每隔15毫秒触发,尽量使升高的效果看起来平滑 Thread.sleep(15); } catch (InterruptedException e) { System.err.println("InterruptedException!线程关闭"); this.interrupt(); } } } }; }
Configuration 类
一个普通的activity,创建了五个柱状图用于测试。第一个view = new ConfigurationView(this, 100, "温度/℃", false, false);没有使用动画效果。
package org.gmy.view.config; import org.gmy.view.R; import android.app.Activity; import android.os.Bundle; import android.view.Gravity; import android.view.ViewGroup.LayoutParams; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TableRow; public class Configuration extends Activity { public static final int WIDTH = 280; public static final int HEIGHT = 250; private ConfigurationView view, view1, view2, view3, view4; private LinearLayout layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.config_dialog); layout = (LinearLayout) findViewById(R.id.configLayout); view = new ConfigurationView(this, 100, "温度/℃", false, false); layout.addView(view, new LayoutParams(50, LayoutParams.FILL_PARENT)); view1 = new ConfigurationView(this, 100, "电量/%", true); layout.addView(view1, new LayoutParams(50, LayoutParams.FILL_PARENT)); view2 = new ConfigurationView(this, 80, "电量/%", true); layout.addView(view2, new LayoutParams(50, LayoutParams.FILL_PARENT)); view3 = new ConfigurationView(this, 40, "电量/%", true); layout.addView(view3, new LayoutParams(50, LayoutParams.FILL_PARENT)); view4 = new ConfigurationView(this, 2, "电量/%", true); layout.addView(view4, new LayoutParams(50, LayoutParams.FILL_PARENT)); } }
config_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="280dip" android:layout_height="250dip" android:padding="10dip" android:layout_gravity="center_horizontal" android:background="@drawable/dialog_alert_bg2" > <TextView android:id="@+id/configTitle" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="柱状图" android:textSize="18dip" android:textColor="#fdb814" /> <LinearLayout android:orientation="horizontal" android:id="@+id/configLayout" android:layout_width="260dip" android:layout_height="220dip" > </LinearLayout> </LinearLayout>
AndroidManifest.xml 使用了对话框的主题
<activity android:name=".Configuration" android:label="@string/app_name" android:theme="@android:style/Theme.Dialog" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>