教你使用RecyclerView畫柱狀圖
最近項目要用到”變色且能橫向滑動的柱狀圖”,如上圖,首先想到的是網上找一篇柱狀圖來改,但看完幾篇文章後內心是崩潰的,因爲不光要畫這五顏六色的柱狀圖,還要將其用在RecyclerView中,使其隨着RecyclerView能上下滾動,這就可能會產生滑動衝突,還得自己處理衝突,雖然咱也會處理衝突,但項目要趕時間就放棄了這種方法。二是想到既然是柱狀圖,我們可否用ProgressBar,只需要用垂直的ProgressBar作爲橫向的RecyclerView的item即可,而用過RecyclerView的都知道,橫向的RecyclerView與縱向的RecyclerView是不會有滑動衝突的。SO DO IT !!!
畫柱狀圖座標軸
既然是柱狀圖,那首先是畫x,y軸了,x,y軸我們用view的寬高爲0.5dp的直線來畫如下,然後再放一個RecyclerView就可以了,(R.layout.activity_main)代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/chart"
android:layout_width="match_parent"
android:layout_height="200dp">
<View
android:id="@+id/view_y"
android:layout_width="0.5dp"
android:layout_height="match_parent"
android:layout_marginBottom="20dp"
android:layout_marginLeft="40dp"
android:layout_marginTop="30dp"
android:background="#666" />
<View
android:id="@+id/view_x"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_alignBottom="@+id/view_y"
android:layout_marginLeft="40dp"
android:background="#666" />
<TextView
android:id="@+id/text_low"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="30dp"
android:layout_marginLeft="5dp"
android:gravity="right"
android:minWidth="20dp"
android:text="低"
android:drawablePadding="2dp"
android:textSize="10sp" />
<TextView
android:id="@+id/text_mid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="95dp"
android:layout_marginLeft="5dp"
android:gravity="right"
android:minWidth="20dp"
android:text="中"
android:drawablePadding="2dp"
android:textSize="10sp" />
<TextView
android:id="@+id/text_hi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="150dp"
android:layout_marginLeft="5dp"
android:gravity="right"
android:minWidth="20dp"
android:drawablePadding="2dp"
android:text="高"
android:textSize="10sp" />
<android.support.v7.widget.RecyclerView
android:id="@+id/rcv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_marginLeft="45dp">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
畫柱狀圖的柱子
其次就是我們的重點,adapter的item的佈局。上圖柱狀圖文字在下,進度在上,因此我們可以用相對佈局將ProgressBar放置在TextView的上方即可,代碼如下:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="50dp"
android:id="@+id/rl_chart_item"
android:layout_height="match_parent">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="11sp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:singleLine="true"
android:maxLines="1"
android:ellipsize="end"
android:text="name"
android:textColor="#999"/>
<ProgressBar
android:id="@+id/pb_vertical"
android:layout_width="20dp"
android:layout_height="150dp"
android:indeterminateOnly="false"
android:layout_above="@+id/name"
android:max="100"
android:progress="60"
android:layout_alignParentBottom="true"
android:layout_marginBottom="21dp"
android:layout_centerHorizontal="true"
android:progressDrawable="@drawable/progress_normal" />
</RelativeLayout>
這兒可能部分使用ProgressBar較少的小夥伴會有疑問,ProgressBar不是水平的嗎,怎麼在你這兒就變成垂直的了,其實關鍵在於progressDrawable我們將drawable的剪裁方向設置爲垂直且從下往上剪裁,progress_normal代碼如下,代碼很簡單就不解釋了:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#00000000" />
<corners android:radius="5dip" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape>
<solid android:color="#00000000" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<!-- 定義ClipDrawable的剪裁方向爲垂直,gravity="bottom" 從下往上 -->
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape android:shape="rectangle">
<solid android:color="#7ddd5c" />
</shape>
</clip>
</item>
</layer-list>
實現帶有柱狀圖的adapter
接下來就很簡單了,寫一個使用上面的item佈局的adapter即可。這兒需要注意的是,柱狀圖是多種顏色的,因此爲了讓ProgressBar有多鍾顏色,我們是通過爲adapter的ProgressBar設置不同drawable來實現的。代碼如下,代碼很簡單,寫過adapter的都能看懂,不再進一步解釋:
public class BarAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final LayoutInflater mLayoutInflater;
private List<ChartData> mDatas;
private float mLowStandard;
private float mHighStandard;
private Context mContext;
private int indexSelected = -1;
public BarAdapter(Context context, float lowStandard, float highStandard,List<ChartData> mDatas) {
mLayoutInflater = LayoutInflater.from(context);
mContext = context;
mLowStandard = lowStandard;
mHighStandard = highStandard;
this.mDatas=mDatas;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewHolder holder = new ViewHolder(mLayoutInflater.inflate(R.layout.bar_chart_item, parent, false));
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ChartData data = mDatas.get(position);
TextView tv_name = ((ViewHolder) holder).getView(R.id.name);
if(position == indexSelected){ //當用戶選中時改變文字顏色
tv_name.setTextColor(Color.RED);
} else {
tv_name.setTextColor(Color.GRAY);
}
ProgressBar progressBar = ((ViewHolder) holder).getView(R.id.pb_vertical);
float pro = data.getProgress();
progressBar.setVisibility(View.VISIBLE);
if (pro > mHighStandard) {//大於“高”時使用一種顏色的Drawable
progressBar.setProgressDrawable(ContextCompat.getDrawable(mContext, R.drawable.progress_high));
} else if (pro < mLowStandard) {
progressBar.setProgressDrawable(ContextCompat.getDrawable(mContext, R.drawable.progress_low));
} else {//小於“低”時使用一種顏色的Drawable
progressBar.setProgressDrawable(ContextCompat.getDrawable(mContext, R.drawable.progress_normal));
}
progressBar.setProgress(Math.round(pro));
tv_name.setText(data.getName());
}
@Override
public int getItemCount() {
if (mDatas == null) {
return 0;
}
return mDatas.size();
}
public void setSelected(int position) {
if(indexSelected == -1){
indexSelected = position;
notifyItemChanged(indexSelected);
} else {
int a = indexSelected;
indexSelected = position;
notifyItemChanged(indexSelected);
notifyItemChanged(a);
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View view) {
super(view);
}
public void setText(int viewId, String text){
TextView tv = (TextView) itemView.findViewById(viewId);
tv.setText(text);
}
public <T extends View> T getView(int viewId){
return (T) itemView.findViewById(viewId);
}
}
}
使用柱狀圖
其次就是使用我們的adapter,這就更簡單了,我直接給出代碼了。
public class MainActivity extends AppCompatActivity {
protected View viewY;
protected View viewX;
protected TextView textLow;
protected TextView textMid;
protected TextView textHi;
protected RecyclerView rcv;
protected RelativeLayout chart;
BarAdapter mdapter;
List<ChartData> mDatas=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_main);
initView();
initData();
initAdapter();
}
private void initView() {
viewY = (View) findViewById(R.id.view_y);
viewX = (View) findViewById(R.id.view_x);
textLow = (TextView) findViewById(R.id.text_low);
textMid = (TextView) findViewById(R.id.text_mid);
textHi = (TextView) findViewById(R.id.text_hi);
rcv = (RecyclerView) findViewById(R.id.rcv);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
rcv.setHasFixedSize(true);
rcv.setLayoutManager(linearLayoutManager);
chart = (RelativeLayout) findViewById(R.id.chart);
}
private void initData(){
for (int i=1;i<=25;i++){
ChartData item=new ChartData();
item.setName("第"+i+"個");
item.setProgress(i*4);
mDatas.add(item);
}
}
private void initAdapter(){
mdapter = new BarAdapter(this, 25, 75,mDatas);
rcv.setAdapter(mdapter);
}
}
總結
到此我們一個“高難度”的柱狀圖就這麼簡單的實現了。其實很多看似複雜的控件都與這個柱狀圖一樣,是可以通過現有控件簡單的組合來實現的,不必非得你會自定義,就看平時有沒有多角度的去積累。
代碼下載
上次代碼上傳到csdn,有人無法下載代碼,就說我是騙積分的,這次專門註冊了github的,不會被說了吧。
https://github.com/yxkrrhx/histogramdemo