使用权重实现柱状图

本文介绍了如何利用权重实现横向和纵向柱形图。通过RecycleView和自定义item布局,详细展示了设置权重来创建柱形图的过程。同时,提到了使用ViewPager实现类似QQ附近人的效果,并提供了相关代码片段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上图
这里写图片描述
这里写图片描述

这里面的横向和竖向的都是使用权重实现的,一会会把代码贴出来,下面的那个viewpager是拽网上的

横向柱形图的实现

这里使用RecycleView实现的。其中item布局是关键。需要依据权重。不多说,直接上代码

    /**
 * 描述:
 * 作者:Marc on 2016/6/17 11:13
 * 邮箱:aliali_ha@yeah.net
 */
public class HoriAdapter extends RecyclerView.Adapter<HoriAdapter.MyViewHolder> {
    private ArrayList<String> name;
    private ArrayList<String> count;
    private Context mContext;

    public HoriAdapter(ArrayList<String> name, ArrayList<String> count, Context mContext) {
        this.name = name;
        this.count = count;
        this.mContext = mContext;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.hori_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        String sName = name.get(position);
        int sCount = Integer.parseInt(count.get(position));
        int spaceHeight = ScreenUtils.dip2px(mContext, 20f);//条形高
        int progressWeight = (int) (100 * 1.0 * sCount / 100);//计算权重
        holder.progressBar.setLayoutParams(new LinearLayout.LayoutParams(0, spaceHeight, progressWeight));
        holder.space.setLayoutParams(new LinearLayout.LayoutParams(0, spaceHeight, 100 - progressWeight));
        holder.name.setText(sName);
        holder.count.setText(sCount + "人");
    }

    @Override
    public int getItemCount() {
        return name.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        @Bind(R.id.disease_type_name)
        TextView name;

        @Bind(R.id.progress)
        View progressBar;

        @Bind(R.id.disease_type_count)
        TextView count;

        @Bind(R.id.space)
        View space;

        public MyViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}

接下来是item的布局了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:padding="15dp">

    <TextView
        android:id="@+id/disease_type_name"
        android:layout_width="78sp"
        android:layout_height="wrap_content"
        android:layout_marginRight="27dp"
        android:text="名字"
        android:textColor="#797b80"
        android:textSize="13sp" />
    <!-- 进度条-->
    <View
        android:id="@+id/progress"
        android:layout_width="1dp"
        android:layout_height="6dp"
        android:background="@drawable/count_type_progress" />
    <!-- 显示数值-->
    <TextView
        android:id="@+id/disease_type_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:text="676人"
        android:textColor="#333333"
        android:textSize="13sp" />
    <!--右侧空白 -->
    <View
        android:id="@+id/space"
        android:layout_width="0dp"
        android:layout_height="6dp" />
</LinearLayout>

其中count_type_progress的drawable文件

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />
    <solid android:color="@color/aat_blue" />
</shape>

其他的就是设置recycleview的内容了

  mRecycleView.setHasFixedSize(true);
        mManager = new LinearLayoutManager(this);
        mRecycleView.setItemAnimator(new DefaultItemAnimator());
        mRecycleView.setLayoutManager(mManager);
        mHoriAdapter = new HoriAdapter(name, count, this);
        mRecycleView.setAdapter(mHoriAdapter);
布局
<android.support.v7.widget.RecyclerView
            android:id="@+id/hori_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:scrollbars="vertical"
            />

上面是实现的横向的柱形图的样子

下面实现纵向的柱形图的样子(PS:因为项目需要的没那么麻烦,所以没考虑用图表实现)

关键也是权重

public class Hori2Adapter extends RecyclerView.Adapter<Hori2Adapter.MyViewHolder> {
    private ArrayList<String> name;
    private ArrayList<String> count;
    private Context mContext;

    public Hori2Adapter(ArrayList<String> name, ArrayList<String> count, Context mContext) {
        this.name = name;
        this.count = count;
        this.mContext = mContext;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.hori_item_vertial, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        String sName = name.get(position);
        int sCount = Integer.parseInt(count.get(position));
        int spaceWidth = ScreenUtils.dip2px(mContext, 20f);//条形宽度
        int progressWeight = (int) (100 * 1.0 * sCount / 100);//计算权重   //这个100 你可以设置成你们数据的最大值
    //关键地方了
        holder.progressBar.setLayoutParams(new LinearLayout.LayoutParams(spaceWidth, 0, progressWeight));
        holder.space.setLayoutParams(new LinearLayout.LayoutParams(spaceWidth, 0, 100 - progressWeight));
        holder.grade.setText(sName);
        holder.count.setText(sCount + "人");
    }

    @Override
    public int getItemCount() {
        return name.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        @Bind(R.id.tv_grade)
        TextView grade;

        @Bind(R.id.progress)
        View progressBar;

        @Bind(R.id.tv_type_count)
        TextView count;

        @Bind(R.id.space)
        View space;

        public MyViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}
//布局
<android.support.v7.widget.RecyclerView
        android:id="@+id/hori_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:padding="5dp"
        android:scrollbars="horizontal" />
  //代码中
 mRecycleView.setHasFixedSize(true);
        mManager = new LinearLayoutManager(getActivity());
        mManager.setOrientation(LinearLayoutManager.HORIZONTAL);//横向
        mRecycleView.setItemAnimator(new DefaultItemAnimator());
        mRecycleView.setLayoutManager(mManager);
        mAdapter = new Hori2Adapter(mName, mCount, getActivity());
        mRecycleView.setAdapter(mAdapter);

//item条目布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="bottom"
    android:orientation="vertical"
    android:padding="15dp">
    //空白占比
    <View
        android:id="@+id/space"
        android:layout_width="6dp"
        android:layout_height="0dp" />
    <!-- 显示人数-->
    <TextView
        android:id="@+id/tv_type_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="15人"
        android:textColor="#797b80"
        android:textSize="13sp" />

    <!-- 具体进度-->
    <View
        android:id="@+id/progress"
        android:layout_width="6dp"
        android:layout_height="1dp"
        android:background="@drawable/count_type_progress" />

    <TextView
        android:id="@+id/tv_grade"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="8dp"
        android:text="高一"
        android:textColor="#333333"
        android:textSize="13sp" />

</LinearLayout>

这样子就实现了 纵向的柱形图
最下面的那个类似QQ附近人的。是看网上帖子,使用viewpager实现的,也一并贴出来
首先是自定义的VIEWPAGER
“java
/** 使用viewpager实现类似QQ附近的人
*/
public class CustomViewPager extends ViewPager {
private long downTime;
private float LastX;
private float mSpeed;

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

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

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    float x = ev.getX();
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downTime = System.currentTimeMillis();
            LastX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            x = ev.getX();
            break;
        case MotionEvent.ACTION_UP:
            //计算得到手指从按下到离开的滑动速度
            mSpeed = (x - LastX) * 1000 / (System.currentTimeMillis() - downTime);
            break;
    }
    return super.dispatchTouchEvent(ev);
}

public float getSpeed() {
    return mSpeed;
}

public void setSpeed(float mSpeed) {
    this.mSpeed = mSpeed;
}
}

page切换动画

public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.70f;
    private static final float MIN_ALPHA = 0.5f;

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
        int pageHeight = view.getHeight();
        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(MIN_ALPHA);
            view.setScaleX(MIN_SCALE);
            view.setScaleY(MIN_SCALE);
        } else if (position <= 1) { // [-1,1]
            // Modify the default slide transition to shrink the page as well
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
            if (position < 0) {
                view.setTranslationX(horzMargin - vertMargin / 2);
                view.setScaleX(1 + 0.3f * position);
                view.setScaleY(1 + 0.3f * position);
            } else {
                view.setTranslationX(-horzMargin + vertMargin / 2);

                view.setScaleX(1 - 0.3f * position);
                view.setScaleY(1 - 0.3f * position);
            }

            // Scale the page down (between MIN_SCALE and 1)

            // Fade the page relative to its size.
            view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setScaleX(MIN_SCALE);
            view.setScaleY(MIN_SCALE);
            view.setAlpha(MIN_ALPHA);
        }
    }
}

手势滑动类

public class FixedSpeedScroller extends Scroller {
    private int mDuration = 1000;

    public FixedSpeedScroller(Context context, AccelerateInterpolator accelerateInterpolator) {
        super(context,accelerateInterpolator);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        super.startScroll(startX, startY, dx, dy,mDuration);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        super.startScroll(startX, startY, dx, dy, mDuration);
    }
    public void setmDuration(int time) {
        mDuration = time;
    }

    public int getmDuration() {
        return mDuration;
    }
}

完整的xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/hori_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:padding="5dp"
        android:scrollbars="horizontal" />

    <View
        android:layout_width="match_parent"
        android:layout_height="3dp"
        android:background="@android:color/holo_red_light" />

    <RelativeLayout
        android:id="@+id/ry_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="25dp"
        android:layout_weight="1"
        android:clipChildren="false">

        <com.marc.chatpicture.widget.CustomViewPager
            android:id="@+id/vp"
            android:layout_width="130dp"
            android:layout_height="160dp"
            android:layout_centerInParent="true"
            android:layout_marginLeft="120dp"
            android:layout_marginRight="120dp" />
    </RelativeLayout>
</LinearLayout>

viewpager适配器

/**
 * 描述:
 * 作者:Marc on 2016/6/24 09:53
 * 邮箱:aliali_ha@yeah.net
 */
public class ViewpagerAdapter extends PagerAdapter {
    private SparseArray<Info> mDatas;
    private Context mContext;
    private LayoutInflater inflater;

    public ViewpagerAdapter(SparseArray<Info> mDatas, Context mContext) {
        this.mDatas = mDatas;
        this.mContext = mContext;
        inflater = LayoutInflater.from(mContext);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        final Info info = mDatas.get(position);
        //设置一大堆演示用的数据,数据啥的大家懂得,按照自己的来就好,这里就直接拿大神的了。项目紧
        View view = inflater.inflate(R.layout.viewpager_layout,null);
        ImageView ivPortrait = (ImageView) view.findViewById(R.id.iv);
        ImageView ivSex = (ImageView) view.findViewById(R.id.iv_sex);
        TextView tvName = (TextView) view.findViewById(R.id.tv_name);
        TextView tvDistance = (TextView) view.findViewById(R.id.tv_distance);
        tvName.setText(info.getName());
        tvDistance.setText(info.getDistance() + "km");
        ivPortrait.setImageResource(info.getPortraitId());
        if (info.getSex()) {
            ivSex.setImageResource(R.drawable.girl);
        } else {
            ivSex.setImageResource(R.drawable.boy);
        }
        ivPortrait.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext, "这是 " + info.getName() + " >.<", Toast.LENGTH_SHORT).show();
            }
        });
        container.addView(view);
        return view;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View) object;
        container.removeView(view);
    }
}

Fragment中

/**
 * 描述:
 * 作者:Marc on 2016/6/24 08:50
 * 邮箱:aliali_ha@yeah.net
 */
public class SampleFragment extends RxFragment implements ViewPager.OnPageChangeListener {
    LinearLayoutManager mManager;
    @Bind(R.id.hori_recyclerview)
    RecyclerView mRecycleView;

    @Bind(R.id.vp)
    CustomViewPager viewPager;
    @Bind(R.id.ry_container)
    RelativeLayout ryContainer;

    private ArrayList<String> mName;
    private ArrayList<String> mCount;
    private Hori2Adapter mAdapter;

    private String[] mNames = {"ImmortalZ", "唐马儒", "王尼玛", "张全蛋", "蛋花", "王大锤", "叫兽", "哆啦A梦"};
    private int[] mImgs = {R.drawable.len, R.drawable.leo, R.drawable.lep,
            R.drawable.leq, R.drawable.ler, R.drawable.les, R.drawable.mln, R.drawable.mmz, R.drawable.mna,
            R.drawable.mnj, R.drawable.leo, R.drawable.leq, R.drawable.les, R.drawable.lep};

    private int mPosition;
    private FixedSpeedScroller scroller;
    private SparseArray<Info> mDatas = new SparseArray<>();
    private ViewpagerAdapter mViewPagerAdapter;
    private static final String TAG = "SampleFragment";

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_sample, null);
        ButterKnife.bind(this, view);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initData();
        initRecycle();
        /**
         * 将Viewpager所在容器的事件分发交给ViewPager
         */
        ryContainer.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return viewPager.dispatchTouchEvent(event);
            }
        });
    }

    private void initRecycle() {
        mRecycleView.setHasFixedSize(true);
        mManager = new LinearLayoutManager(getActivity());
        mManager.setOrientation(LinearLayoutManager.HORIZONTAL);//横向
        mRecycleView.setItemAnimator(new DefaultItemAnimator());
        mRecycleView.setLayoutManager(mManager);
        mAdapter = new Hori2Adapter(mName, mCount, getActivity());
        mRecycleView.setAdapter(mAdapter);

        mViewPagerAdapter = new ViewpagerAdapter(mDatas, getActivity());
        viewPager.setAdapter(mViewPagerAdapter);
        //设置缓存数为展示的数目
        viewPager.setOffscreenPageLimit(mImgs.length);
        viewPager.setPageMargin(getResources().getDimensionPixelOffset(R.dimen.viewpager_margin));
        //设置切换动画
        viewPager.setPageTransformer(true, new ZoomOutPageTransformer());
        viewPager.addOnPageChangeListener(this);
        setViewPagerSpeed(250);

    }

    /**
     * 设置viewpager切换速度
     *
     * @param duration
     */
    private void setViewPagerSpeed(int duration) {
        try {
            Field field = ViewPager.class.getDeclaredField("mScroller");
            field.setAccessible(true);
            scroller = new FixedSpeedScroller(getActivity(), new AccelerateInterpolator());
            field.set(viewPager, scroller);
            scroller.setmDuration(duration);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private void initData() {
        mName = new ArrayList<>();
        mCount = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            mName.add("MARC" + i);
            mCount.add(new Random().nextInt(99) + "");
        }
        for (int i = 0; i < mImgs.length; i++) {
            Info info = new Info();
            info.setPortraitId(mImgs[i]);
            info.setAge(((int) Math.random() * 25 + 16) + "岁");
            info.setName(mNames[(int) (Math.random() * mNames.length)]);
            info.setSex(i % 3 == 0 ? false : true);
            info.setDistance(Math.round((Math.random() * 10) * 100) / 100);
            mDatas.put(i, info);
        }
    }


    @Override
    public void onDestroyView() {
        super.onDestroyView();
        ButterKnife.unbind(this);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        mPosition = position;
    }

    @Override
    public void onPageSelected(int position) {
        LogUtils.e(TAG, "当前位置 " + mPosition);
        LogUtils.e(TAG, "速度 " + viewPager.getSpeed());
        //当手指左滑速度大于2000时viewpager右滑(注意是item+2)
        if (viewPager.getSpeed() < -1800) {

            viewPager.setCurrentItem(mPosition + 2);
            LogUtils.e(TAG, "位置 " + mPosition);
            viewPager.setSpeed(0);
        } else if (viewPager.getSpeed() > 1800 && mPosition > 0) {
            //当手指右滑速度大于2000时viewpager左滑(注意item-1即可)
            viewPager.setCurrentItem(mPosition - 1);
            LogUtils.e(TAG, "位置 " + mPosition);
            viewPager.setSpeed(0);
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
}

PS:网上的还有个雷达图,这里用不到,大家可以自行搜索

资源下载

### ECharts 柱状图分段显示配置 为了实现ECharts柱状图的分段显示,可以采用普通柱状图与象形柱状图相结合的方式。这种方式不仅能够展示分段效果,还能保持每个柱子的颜色渐变特性[^2]。 #### 实现方案概述 具体来说,在某个区间上的多组数据可以通过设置多个系列来表示不同区间的柱条。对于每一个柱条,其位置由前一组数据之和决定,以此类推形成连续的分段视觉效果。此外,利用`itemStyle`属性下的线性渐变功能可赋予各段独特的色彩过渡[^4]。 #### 关键配置项解析 - **series.type**: 设置为'bar'(柱状图)或'pictorialBar'(象形柱状图),依据实际需求选择。 - **data**: 定义每一栏的具体数值列表;当处理分段情况时,应分别计算并输入各个片段对应的值。 - **itemStyle.color**: 使用linearGradient定义颜色变化规律,支持指定起点终点坐标及中间经过点的颜色权重分布。 下面给出一个简单的例子: ```javascript option = { xAxis: {type: 'category', show: false}, yAxis: {}, series : [ // 底部基础柱状图 { type: 'bar', stack: '总量', itemStyle:{ color:new echarts.graphic.LinearGradient( 0, 0, 0, 1, [{ offset: 0, color: '#ffeda6' }, { offset: 1, color: '#fe7f5a' }] ) }, data:[3] }, // 上层分段之一 { name:'分段一', type: 'pictorialBar', symbolSize:[20,'100%'], symbolOffset:[0,-5], zlevel:2, label:{show:true,position:'top'}, data:[{value:5,itemStyle:{color:'#bdefff'}}] } // 可继续添加更多分段... ] }; ``` 上述代码展示了如何创建具有底部渐变色的基础柱以及位于顶部的第一段彩色标记。通过调整`symbloSize`, `symbolOffset`等参数可以使这些附加元素更好地贴合原始柱体形状,并且不影响整体美观度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值