心形进度条

废话不多说,先上效果图:

这个进度就是模拟心形填充的过程


实现原理是:首先将空心形图片绘制出来,然后根据进度大小再将实心的心形图片一部分一部分的绘制出来。也就是两张完全相同大小的空心图和圆心图重叠绘制,利用canvas的clipRect绘制实心部分,实现进度条效果。


首先在res->values先新建一个文件atrrs.xml,然后定义两个属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="HeartProgressBar">
        <attr name="max" format="integer"></attr>
        <attr name="progress" format="integer"></attr>
    </declare-styleable>
</resources>

max是最大进度值,progress是当前进度。

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;

import com.helen.funnyview.R;


/**
 * Created by Helen on 2015/5/14.
 */
public class HeartProgressBar extends View{
    private Bitmap mHeartBitmap;//空心图片
    private Bitmap mHeartedBitmap;//实心图
    private Paint mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
    private int progress=0;//当前进度
    private int max=100;//最大进度
    private boolean isFinish=false;//是否填充完成
    private boolean isAutoFill=false;//是否自动填充
    public HeartProgressBar(Context context) {
        super(context);
        init();
    }

    public HeartProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.HeartProgressBar);
        progress=a.getInteger(R.styleable.HeartProgressBar_progress,0);
        max=a.getInteger(R.styleable.HeartProgressBar_max,100);
        if(max<=0){
            max=100;
        }
        a.recycle();
    }

    public HeartProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        if(mHeartBitmap==null){
            mHeartBitmap=BitmapFactory.decodeResource(getResources(), R.mipmap.heart);
        }
        if(mHeartedBitmap==null){
            mHeartedBitmap= BitmapFactory.decodeResource(getResources(), R.mipmap.hearted);
        }
    }
    @Override
    protected void onDraw(Canvas canvas) {
        final int width=getWidth();//mHeartBitmap.getWidth();
        final int height=getHeight();//mHeartBitmap.getHeight();
        float percent=progress*1.0f/max;//进度百分比
        if(percent>=1){
            percent=1;
        }
        canvas.save();
        //绘制空心图
        canvas.drawBitmap(mHeartBitmap, 0, 0,mPaint);
        //计算绘制实心图的范围
        canvas.clipRect(0, height * (1 - percent), width, height);
        //绘制实心图
        canvas.drawBitmap(mHeartedBitmap, 0, 0, mPaint);
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //int widthMode=MeasureSpec.getMode(widthMeasureSpec);
        //if(widthMode==MeasureSpec.AT_MOST){//layout_width=wrap_content
            //设置控件宽高跟图片一样
            setMeasuredDimension(mHeartBitmap.getWidth(), mHeartBitmap.getHeight());
        //}
        //setMeasuredDimension(getMeasureSize(widthMeasureSpec, true), getMeasureSize(heightMeasureSpec, true));
    }

    private int getMeasureSize(int spec,boolean isWidth){
        int size=MeasureSpec.getSize(spec);
        int mode=MeasureSpec.getMode(spec);
        if(mode==MeasureSpec.AT_MOST){
            if(isWidth) {
                size =mHeartBitmap.getWidth();
            }else{
                size=mHeartBitmap.getHeight();
            }
        }
        return size;
    }


    /**
     * 设置当前进度
     * @param progress
     */
    public void setProgress(int progress) {
        if(isAutoFill) return;
        this.progress = progress;
        if(!isFinish) {

            invalidate();
        }
        if(progress>=max){
            isFinish=true;
        }
    }
    public int getProgress() {
        return progress;
    }
    /**
     * 是否完成
     * @return
     */
    public boolean isFinish() {
        return isFinish;
    }

    public boolean isAutoFill() {
        return isAutoFill;
    }

    /**
     * 设置最大进度值
     */
    public void setMax(int max) {
        this.max = max;
    }

    public int getMax() {
        return max;
    }

    /**
     * 开启自动填充
     */
    public void startAutoFill(){
        isAutoFill=true;
        final int step=10;
        final Handler handler=new Handler();
        handler.post(new Runnable() {
            @Override
            public void run() {
                progress += step;
                invalidate();
                if (progress >= max) {
                    isFinish = true;
                }
                if (!isFinish()) {
                    handler.postDelayed(this, 100 - progress);
                } else {
                    handler.removeCallbacks(this);
                }
            }
        });
    }
}

然后就是使用它了。首先是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.helen.funnyview.view.HeartProgressBar
        android:id="@+id/bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        app:progress="50"
        app:max="150"
        />
</RelativeLayout>

设置了起始进度为50,最大进度为150
接着是activity内容:

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;

import com.helen.funnyview.R;
import com.helen.funnyview.view.HeartProgressBar;

/**
 * Created by Helen on 2015/5/14 16:56.
 * TODO
 */
public class HeartProgressBarActivity extends Activity{
    private HeartProgressBar bar;
    private Handler handler=new Handler();
    private int progress=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_heart_progress_bar);
        bar=(HeartProgressBar)findViewById(R.id.bar);
        progress=bar.getProgress();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                progress+=5;
                bar.setProgress(progress);
                if(!bar.isFinish()) {
                    handler.postDelayed(this, 500);
                }else{
                    handler.removeCallbacks(this);
                }
            }
        },3000);
        //bar.startAutoFill();
    }
}

handler是模拟一个网络请求,进度加载的过程。这样就实现了开始那种效果了。
还有就是,该控件也可以用于类似于‘收藏’的功能,就是一开始没有收藏是空心的,点击收藏后就动态填充了心形,也就是上面注释掉的代码startAutoFill()方法。
需要源码的请戳这里

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在PyCharm中实现心形,你可以按照以下步骤进行操作: 1. 在PyCharm中创建一个新的Python文件。 2. 导入所需的库(例如Tkinter和random)。 3. 定义一个类(例如Heart)来表示心形。 4. 在Heart类中,创建一个方法(例如build),用于生成心形的点坐标。 5. 在build方法中,使用随机数生成器来生成心形的点坐标。你可以使用心形函数来计算x和y的值。 6. 在Heart类中,创建一个方法(例如draw),用于绘制心形。 7. 在draw方法中,使用Tkinter的Canvas来绘制心形的点。 8. 在主程序中,创建一个Tkinter的窗口,并将Canvas放置在窗口中。 9. 创建一个Heart的实例,并调用draw方法来绘制心形。 10. 启动窗口的事件循环,以显示绘制的心形。 例如,以下是一个简单的示例代码,实现了在PyCharm中绘制心形: ```python from tkinter import * import random from math import pi CANVAS_WIDTH = 400 CANVAS_HEIGHT = 400 class Heart: def __init__(self): self._points = set() def build(self, number): for _ in range(number): t = random.uniform(0, 2 * pi) x, y = self.heart_function(t) self._points.add((x, y)) def heart_function(self, t): # 心形方程 x = 16 * pow(sin(t), 3) y = 13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t) return x, y def draw(self, canvas): for x, y in self._points: canvas.create_rectangle(x, y, x+1, y+1, fill='red') if __name__ == '__main__': root = Tk() root.title("绘制心形") canvas = Canvas(root, bg='white', height=CANVAS_HEIGHT, width=CANVAS_WIDTH) canvas.pack() heart = Heart() heart.build(1000) heart.draw(canvas) root.mainloop() ``` 这段代码通过使用Tkinter库和数学函数来绘制心形。它创建了一个Heart类来表示心形,并使用build方法来生成心形的点坐标。然后,它在draw方法中使用Canvas对象来绘制心形。在主程序中,它创建了一个窗口,并将Canvas放置在窗口中。最后,它创建了一个Heart的实例,并调用draw方法来绘制心形。启动窗口的事件循环,以显示绘制的心形。 请注意,这只是一个简单的示例代码,你可以根据自己的需求进行修改和扩展。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [pycharm实现心形](https://blog.csdn.net/MTRWW/article/details/131209951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值