【Android UI】自定义圆形SeekBar和自定义Dialog的结合使用

最近要做一个比较有趣的效果,就是将android手机设置的条形的SeekBar换成圆形的SeekBar,这里我不讲怎么将定制系统的设置rom,但如果有人想了解设置里面的显示可以看看这篇博客,只讲怎么自定义圆形SeekBar和自定义Dialog,虽然网上有很多这方面的资料,但不系统,所以在这里总结下,方面以后观看。

自定义圆形SeekBar

关于圆形SeekBar我是在GitHub上下载的一个开源项目,项目地址,里面有详细的使用说明和参数含义。在这里,我也贴一下代码和使用步骤。

首先,我们从网站下载代码,看看解压包里面有CircularSeekBar.java和attrs.xml文件,一眼看下去就知道attrs.xml是属性的定义,CircularSeekBar.java是自定义圆形SeekBar的实现。下面贴一下attrs.xml看下有那些属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="CircularSeekBar">
        <attr name="progress" format="integer"></attr>
        <attr name="max" format="integer"></attr>
        <attr name="move_outside_circle" format="boolean"></attr>
        <attr name="maintain_equal_circle" format="boolean"></attr>
        <attr name="use_custom_radii" format="boolean"></attr>
        <attr name="lock_enabled" format="boolean"></attr>
        <attr name="circle_x_radius" format="dimension" />
        <attr name="circle_y_radius" format="dimension" />
        <attr name="circle_stroke_width" format="dimension" />
        <attr name="pointer_radius" format="dimension" />
        <attr name="pointer_halo_width" format="dimension" />
        <attr name="pointer_halo_border_width" format="dimension"></attr>
        <attr name="circle_color" format="color"></attr>
        <attr name="circle_progress_color" format="color"></attr>
        <attr name="pointer_color" format="color"></attr>
        <attr name="pointer_halo_color" format="color"></attr>
        <attr name="pointer_halo_color_ontouch" format="color"></attr>
        <attr name="pointer_alpha_ontouch" format="integer"></attr>
        <attr name="start_angle" format="float"></attr>
        <attr name="end_angle" format="float"></attr>
        <attr name="circle_fill" format="color"></attr>
    </declare-styleable>

</resources>

要了解具体的属性看了,可以去GitHub上看下,这里就不累叙了。

之后,我们将自定义的CircularSeekBar.java导入我们的项目,当然attrs.xml也要导入,至于怎么自定义的CircularSeekBar大家可以自己看看源码。

最后,我们来写一个对这个CircularSeekBar的测试。先来看看UI的代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.yzx.circularseekbar.MainActivity" >

    <Button 
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:layout_centerHorizontal="true"
        android:text="弹出对话框"/>
</RelativeLayout>

这段代码没什好讲的,我们再来看看MainActivity的代码:

public class MainActivity extends Activity{
    private SharedPreferences sp;

    private AlertDialog dialog;

    private Timer mTimer;
    private TimerTask mTimerTask;

    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 1:
                dialog.dismiss();
                break;
            default:
                break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void click(View v){
        //Toast.makeText(this, "haha", Toast.LENGTH_LONG).show();
        switch (v.getId()) {
        case R.id.btn1:
            sp = getSharedPreferences("brightness", MODE_PRIVATE);
            showBrightnessDialog();
            break;
        default:
            break;
        }
    }

    private void showBrightnessDialog() {

        //使用Timer来实现3秒自动关闭dialog
        mTimer = new Timer();
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                Message message = new Message();      
                message.what = 1;      
                handler.sendMessage(message);
            }
        };
        //开始一个定时任务
        mTimer.schedule(mTimerTask, 3000);

        AlertDialog.Builder builder = new Builder(this);
        View contentView = View.inflate(this, R.layout.brightness_dialog, null);
        CircularSeekBar seekbar = (CircularSeekBar) contentView.findViewById(R.id.circularSeekBar1);
        int brightnessValue = sp.getInt("brightnessValue", 45);
        seekbar.setProgress(brightnessValue);
        //注册监听事件
        seekbar.setOnSeekBarChangeListener(new OnCircularSeekBarChangeListener() {

            @Override
            public void onProgressChanged(CircularSeekBar circularSeekBar,
                    int progress, boolean fromUser) {
                //在此处修改亮度
                System.out.println("circularSeekBar:"+progress);
            }

            @Override
            public void onStopTrackingTouch(CircularSeekBar seekBar) {
                // TODO Auto-generated method stub
                mTimer = new Timer();
                mTimerTask = new TimerTask() {
                    @Override
                    public void run() {
                        Message message = new Message();      
                        message.what = 1;      
                        handler.sendMessage(message);
                    }
                };
                //开始一个定时任务
                mTimer.schedule(mTimerTask, 3000);

                Editor editor = sp.edit();
                editor.putInt("brightnessValue", seekBar.getProgress());
                editor.commit();
            }

            @Override
            public void onStartTrackingTouch(CircularSeekBar seekBar) {
                // TODO Auto-generated method stub
                mTimer.cancel();
            }

        });
        dialog = builder.create();
        dialog.setView(contentView,0,0,0,0);
        dialog.show();

        //Handle实现过3秒自动关闭dialog。自动关闭对话框的功能主要使用Handler对象来实现,该对象的postDelayed方法用来实现延时多少秒去执行某个任务。
        //有Bug,无论是否操作,Dialog过三秒都会关闭
        /*Handler handler = new Handler();  
        handler.postDelayed(new Runnable() {

            public void run() {  
                dialog.dismiss();  
            }  
        }, 3000);*/

    }
}

我们先贴出brightness_dialog.xml的代码,再来分析下代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res/com.yzx.circularseekbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:background="#000000"
    tools:context="com.yzx.circularseekbar.MainActivity" >

    <TextView 
        android:id="@+id/tv_brightness"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="20sp"
        android:textColor="#0174DF"
        android:text="亮度"/>

    <com.yzx.circularseekbar.CircularSeekBar
        android:id="@+id/circularSeekBar1"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_below="@id/tv_brightness"
        app:circle_x_radius="100dp"
        app:circle_y_radius="100dp"
        app:use_custom_radii="true"
        app:progress="25"
        app:max="100"
        app:pointer_alpha_ontouch="100"
        app:pointer_color="#0174DF"
        app:pointer_halo_color="#880174DF" />

</RelativeLayout>

上面代码达到的效果是,当你点击“弹出对话框”按钮时,弹出圆形SeekBar。如果你不动时,弹出的AlertDialog过三秒就会自动消失,当你拖动圆形SeekBar时,就不会消失,不拖动,过3秒又自动消失。这里面也记录的你的进度条拖动到什么位置了。

要注意,在brightness_dialog.xml中不要忘了一行代码:

xmlns:app="http://schemas.android.com/apk/res/com.yzx.circularseekbar"

实现自动关闭时通过使用Timer来实现的,本来想使用Handle里面的postDelayed来实现,但有一个不管你操不操作,过3秒就会关闭的Bug。Timer的主体代码如下:

//使用Timer来实现3秒自动关闭dialog
mTimer = new Timer();
mTimerTask = new TimerTask() {
    @Override
    public void run() {
        Message message = new Message();      
        message.what = 1;      
        handler.sendMessage(message);
    }
};
//开始一个定时任务
mTimer.schedule(mTimerTask, 3000);

通过在单击“弹出对话框”按钮、onStartTrackingTouch和onStopTrackingTouch的结合使用来实现自动关闭的效果。

运行效果如下:

这里写图片描述

自定义Dialog

在上面的AlertDialog中,有一个隐藏的Bug,当我们单击按钮让弹窗弹出时马上关闭,之后又点击按钮让弹窗弹出,循环几次,就会发现弹窗不可控的情况出现,其根本原因就是我们开启了多个Timer,而在关闭(dismiss)时没有终止Timer造成的。

对与以上的Bug,我们需要自定义Dialog,重写自定义的Dialog中的dismiss方法,让其在每次退出时就终止Timer。
我们现在主UI中添加一个按钮,来调用自定义的Dialog。添加后的完整代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.yzx.circularseekbar.MainActivity" >

    <Button 
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:layout_centerHorizontal="true"
        android:text="弹出对话框"/>

    <Button 
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/btn1"
        android:onClick="click"
        android:layout_centerInParent="true"
        android:text="弹出对话框_自定义" />
</RelativeLayout>

brightness_dialog.xml中的代码不变,而MainActivity的完整代码如下:

public class MainActivity extends Activity{
    private SharedPreferences sp;

    private AlertDialog dialog;
    private MyAlertDialog myDialog;

    private Timer mTimer;
    private TimerTask mTimerTask;

    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 1:
                dialog.dismiss();
                break;
            case 2:
                myDialog.dismiss();
                break;
            default:
                break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void click(View v){
        //Toast.makeText(this, "haha", Toast.LENGTH_LONG).show();
        switch (v.getId()) {
        case R.id.btn1:
            sp = getSharedPreferences("brightness", MODE_PRIVATE);
            showBrightnessDialog();
            break;

        case R.id.btn2:
            sp = getSharedPreferences("brightness", MODE_PRIVATE);
            showMyBrightnessDialog();
            break;

        default:
            break;
        }
    }

    private void showMyBrightnessDialog() {
        myDialog = new MyAlertDialog(MainActivity.this);
        //设置为没有title
        myDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        myDialog.show();

        //使用Timer来实现3秒自动关闭dialog
        mTimer = new Timer();
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                Message message = new Message();      
                message.what = 2;      
                handler.sendMessage(message);
            }
        };
        //开始一个定时任务
        mTimer.schedule(mTimerTask, 3000);
    }

    //重写Dialog,实现每次dismiss时终止定时器
    class MyAlertDialog extends Dialog{

        protected MyAlertDialog(Context context) {
            super(context);
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.brightness_dialog);
            CircularSeekBar seekbar = (CircularSeekBar) findViewById(R.id.circularSeekBar1);
            int brightnessValue = sp.getInt("customBrightnessValue", 45);
            seekbar.setProgress(brightnessValue);
            //注册监听事件
            seekbar.setOnSeekBarChangeListener(new OnCircularSeekBarChangeListener() {

                @Override
                public void onProgressChanged(CircularSeekBar circularSeekBar,
                        int progress, boolean fromUser) {
                    //在此处修改亮度
                    System.out.println("circularSeekBar's progress is :"+progress);
                }

                @Override
                public void onStopTrackingTouch(CircularSeekBar seekBar) {
                    mTimer = new Timer();
                    mTimerTask = new TimerTask() {
                        @Override
                        public void run() {
                            Message message = new Message();      
                            message.what = 2;      
                            handler.sendMessage(message);
                        }
                    };
                    //开始一个定时任务
                    mTimer.schedule(mTimerTask, 3000);

                    Editor editor = sp.edit();
                    editor.putInt("customBrightnessValue", seekBar.getProgress());
                    editor.commit();
                }

                @Override
                public void onStartTrackingTouch(CircularSeekBar seekBar) {
                    mTimer.cancel();
                }

            });
        }

        @Override
        public void dismiss() {
            // 终止所有的定时器
            mTimer.cancel();
            System.out.println("circularSeekBar is auto close.");
            super.dismiss();
        }
    }

    private void showBrightnessDialog() {

        //使用Timer来实现3秒自动关闭dialog
        mTimer = new Timer();
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                Message message = new Message();      
                message.what = 1;      
                handler.sendMessage(message);
            }
        };
        //开始一个定时任务
        mTimer.schedule(mTimerTask, 3000);

        AlertDialog.Builder builder = new Builder(this);
        View contentView = View.inflate(this, R.layout.brightness_dialog, null);
        CircularSeekBar seekbar = (CircularSeekBar) contentView.findViewById(R.id.circularSeekBar1);
        int brightnessValue = sp.getInt("brightnessValue", 45);
        seekbar.setProgress(brightnessValue);
        //注册监听事件
        seekbar.setOnSeekBarChangeListener(new OnCircularSeekBarChangeListener() {

            @Override
            public void onProgressChanged(CircularSeekBar circularSeekBar,
                    int progress, boolean fromUser) {
                //在此处修改亮度
                System.out.println("circularSeekBar:"+progress);
            }

            @Override
            public void onStopTrackingTouch(CircularSeekBar seekBar) {
                // TODO Auto-generated method stub
                mTimer = new Timer();
                mTimerTask = new TimerTask() {
                    @Override
                    public void run() {
                        Message message = new Message();      
                        message.what = 1;      
                        handler.sendMessage(message);
                    }
                };
                //开始一个定时任务
                mTimer.schedule(mTimerTask, 3000);

                Editor editor = sp.edit();
                editor.putInt("brightnessValue", seekBar.getProgress());
                editor.commit();
            }

            @Override
            public void onStartTrackingTouch(CircularSeekBar seekBar) {
                // TODO Auto-generated method stub
                mTimer.cancel();
            }
        });
        dialog = builder.create();
        dialog.setView(contentView,0,0,0,0);
        dialog.show();

        //Handle实现过3秒自动关闭dialog。自动关闭对话框的功能主要使用Handler对象来实现,该对象的postDelayed方法用来实现延时多少秒去执行某个任务。
        //有Bug,无论是否操作,Dialog过三秒都会关闭
        /*Handler handler = new Handler();  
        handler.postDelayed(new Runnable() {

            public void run() {  
                dialog.dismiss();  
            }  
        }, 3000);*/

    }
}

上面的代码主要的部分就是:

@Override
public void dismiss() {
    // 终止所有的定时器
    mTimer.cancel();
    System.out.println("circularSeekBar is auto close.");
    super.dismiss();
}

就是每次调用dismiss时就终止Timer,这样就解决的弹窗的不可控。

源码下载地址:https://github.com/yzhixiang/CircularSeekBar-CustomDialog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值