Android SeekBar自定义使用图片和颜色显示

http://my.oschina.net/amigos/blog/60181


案例使用的图片如下:

                          

1.在res/drawable目录下新增一个xml风格文件,seekbar_define_style.xml

01 <?xml version="1.0" encoding="utf-8"?>
02 <layer-list
03     xmlns:android="http://schemas.android.com/apk/res/android">
04     <!-- 未选中 -->
05     <item
06         android:id="@android:id/background"
07         android:drawable="@drawable/hou"/>
08     <!-- 中 -->
09     <item
10         android:id="@android:id/progress"
11         android:drawable="@drawable/qian"/>
12     <item
13         android:id="@android:id/secondaryProgress"
14         android:drawable="@drawable/qian"/>
15 </layer-list>

2.在res/drawable下定义个seekbar_thumb.xml文件

 

01 <?xml version="1.0" encoding="utf-8"?>
02 <selector xmlns:android="http://schemas.android.com/apk/res/android">       
03         
04     <!-- 按下状态--> 
05     <item   
06         android:state_focused="true"   
07         android:state_pressed="true"   
08         android:drawable="@drawable/ic_launcher" />       
09     <!-- 普通无焦点状态 -拖动按钮--> 
10     <item   
11         android:state_focused="false"   
12         android:state_pressed="false" 
13         android:drawable="@drawable/orbino_icon_pack_006" />             
14     <!-- 有焦点状态--> 
15     <item   
16         android:state_focused="true"   
17         android:state_pressed="false"             
18         android:drawable="@drawable/ios" />        
19     <!-- 有焦点 --> 
20     <item   
21         android:state_focused="true"             
22         android:drawable="@drawable/ios"/>
23 </selector>

3.在res/layut下定义布局资源文件seekbar_define.xml

01 <?xml version="1.0" encoding="utf-8"?>
02 <ScrollView xmlns:android="<a href="http://schemas.android.com/apk/res/android" rel="nofollow">http://schemas.android.com/apk/res/android</a>"
03     android:layout_width="fill_parent"
04     android:layout_height="fill_parent"
05     >
06     <LinearLayout
07         android:layout_width="fill_parent"
08         android:layout_height="fill_parent"
09          android:orientation="vertical"
10         >
11     <TextView
12     android:id="@+id/seekbar_tetview_one"
13     android:layout_width="wrap_content"
14     android:layout_height="wrap_content"
15     android:text="SeekBar自定义"
16     />
17     <TextView
18     android:id="@+id/seekbar_tetview_two"
19     android:layout_width="wrap_content"
20     android:layout_height="wrap_content"
21     android:text="SeekBar拖动时信息提示"
22     />
23     <SeekBar
24     android:layout_width="321px"
25     android:layout_height="wrap_content"
26     android:layout_centerInParent="true"
27     android:maxHeight="20px"
28     android:minHeight="20px"
29     android:paddingLeft="18px"
30     android:paddingRight="18px"
31     android:max="100"
32     android:progressDrawable="@drawable/seekbar_define_style"
33     android:thumb="@drawable/seekbar_thumb"
34     android:id="@+id/seekBar"/>
35  </LinearLayout>
36 </ScrollView>

4.定义java文件通过 引用布局文件:

 

01 package com.test;
02  
03 import android.R.integer;
04 import android.app.Activity;
05 import android.os.Bundle;
06 import android.os.Handler;
07 import android.os.Message;
08 import android.widget.SeekBar;
09 import android.widget.SeekBar.OnSeekBarChangeListener;
10 import android.widget.TextView;
11  
12 public class SeekBarDemo_DefineDemo extends Activity {
13     private SeekBar seekBar;
14     private TextView textView_one, textView_two;
15  
16     @Override
17     protected void onCreate(Bundle savedInstanceState) {
18         super.onCreate(savedInstanceState);
19         setContentView(R.layout.seekbar_define);
20  
21         seekBar = (SeekBar) findViewById(R.id.seekBar);
22  
23         textView_one = (TextView) findViewById(R.id.seekbar_tetview_one);
24  
25         textView_two = (TextView) findViewById(R.id.seekbar_tetview_two);
26  
27         seekBar.setOnSeekBarChangeListener(seekbarChangeListener);
28  
29     }
30  
31     private OnSeekBarChangeListener seekbarChangeListener = new OnSeekBarChangeListener() {
32  
33         // 停止拖动时执行
34         @Override
35         public void onStopTrackingTouch(SeekBar seekBar) {
36             // TODO Auto-generated method stub
37             textView_two.setText("停止拖动了!");
38  
39         }
40  
41         // 在进度开始改变时执行
42         @Override
43         public void onStartTrackingTouch(SeekBar seekBar) {
44             // TODO Auto-generated method stub
45             textView_two.setText("进度开始改变");
46         }
47  
48         // 当进度发生改变时执行
49         @Override
50         public void onProgressChanged(SeekBar seekBar, int progress,
51                 boolean fromUser) {
52             textView_two.setText("正在进行拖动操作,还没有停下来一直再拖动");
53             Message message = new Message();
54  
55             Bundle bundle = new Bundle();// 存放数据
56  
57             float pro = seekBar.getProgress();
58  
59             float num = seekBar.getMax();
60  
61             float result = (pro / num) * 100;
62             bundle.putFloat("key", result);
63  
64             message.setData(bundle);
65  
66             message.what = 0;
67  
68             handler.sendMessage(message);
69  
70         }
71     };
72  
73     /**
74      * 用Handler来更新UI
75      */
76     private Handler handler = new Handler() {
77         @Override
78         public void handleMessage(Message msg) {
79             textView_one.setText("当前拖动位置占 :       "
80                     + msg.getData().getFloat("key") + "/100");
81  
82         }
83  
84     };
85  
86 }

最后执行效果:

 程序启动后的默认显示

 

拖动过程中的显示

 

停止拖动后的显示

 二:使用颜色显示,和尚面是一样的,只有我们定义颜色资源来替代图片资源文件seekbar_define_color_style.xml:如下:

01 <?xml version="1.0" encoding="UTF-8"?>    
02 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">    
03    
04    <item android:id="@android:id/background"
05             android:paddingTop="3px"
06          android:paddingBottom="3px">    
07       <shape>    
08          <corners android:radius="10dip" />    
09          <gradient   
10              android:startColor="#ffffffff" 
11              android:centerColor="#ff000000"    
12              android:endColor="#ff808A87"   
13              android:centerY="0.45"    
14              android:angle="270"/>    
15       </shape>    
16    </item>    
17        
18    <item android:id="@android:id/progress"
19             android:paddingTop="3px"
20          android:paddingBottom="3px" >    
21        <clip>    
22           <shape>    
23               <corners android:radius="10dip" />    
24               <gradient   
25                   android:startColor="#ffffffff" 
26                   android:centerColor="#ffFFFF00"    
27                   android:endColor="#ffAABD00"   
28                   android:centerY="0.45"    
29                   android:angle="270"/>    
30           </shape>    
31        </clip>    
32    </item>    
33  </layer-list>

之后再SeekBar标签使用如下属性进行引入:其他保持不变

1 android:progressDrawable="@drawable/seekbar_define_color_style"

执行效果:

下面一个SeekBar是自定义颜色效果

 

由于SeekBar的属性thumb引入了自定义的seekbar_thumb.xml文件,拖动图标是我们自定义的图片:除去这个属性

1 android:thumb="@drawable/seekbar_thumb"

就回复系统默认状态效果最后效果如下:

拖动按钮系统风格

我们可以通过颜色值再次休息seekbar_thumb.xml文件,使拖动按钮设置成自定义颜色:


----------------------------------------------------------


摘要:做音乐播放器,有时会要求EQ均衡器,但android默认的样式是水平的,这时就需要费点心思了。 先是实现默认SeekBar样式的EQ均衡器: 这是4.0...

 做音乐播放器,有时会要求EQ均衡器,但android默认的样式是水平的,这时就需要费点心思了。

     先是实现默认SeekBar样式的EQ均衡器:

    android手机上实现竖直seekbar的EQ均衡器

      这是4.0以上默认样式的SeekBar,2.3或以下就像是进度条一样。

      要实现这样的效果,其实并不难,先贴上源码:

public class MainActivity extends Activity {
    private MediaPlayer mMediaPlayer;
    private Equalizer mEqualizer;
    private LinearLayout mLayout;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setVolumeControlStream(AudioManager.STREAM_MUSIC);

        mLayout = new LinearLayout(this);
        mLayout.setOrientation(LinearLayout.VERTICAL);
        setContentView(mLayout);

        mMediaPlayer = new MediaPlayer();
        try {
            mMediaPlayer.setDataSource("/sdcard/陪我去流浪.mp3");
            mMediaPlayer.prepare();
            mMediaPlayer.start();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        setEqualize();
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    private void setEqualize() {
        mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
        mEqualizer.setEnabled(true);

        short bands = mEqualizer.getNumberOfBands();

        final short minEqualizer = mEqualizer.getBandLevelRange()[0];
        final short maxEqualizer = mEqualizer.getBandLevelRange()[1];

        for (short i = 0; i < bands; i++) {
            final short band = i;

            TextView freqTextView = new TextView(this);
            freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT));

            freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);

            freqTextView
                    .setText((mEqualizer.getCenterFreq(band) / 1000) + "HZ");
            mLayout.addView(freqTextView);

            LinearLayout row = new LinearLayout(this);
            row.setOrientation(LinearLayout.HORIZONTAL);

            TextView minDbTextView = new TextView(this);
            minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT));

            minDbTextView.setText((minEqualizer / 100) + " dB");

            TextView maxDbTextView = new TextView(this);
            maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT));
            maxDbTextView.setText((maxEqualizer / 100) + " dB");

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);

            SeekBar seekbar = new SeekBar(this);
            seekbar.setLayoutParams(layoutParams);
            seekbar.setMax(maxEqualizer - minEqualizer);
            seekbar.setProgress(mEqualizer.getBandLevel(band));
            seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }

                @TargetApi(Build.VERSION_CODES.GINGERBREAD)
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress,
                        boolean fromUser) {
                    // TODO Auto-generated method stub
                    mEqualizer.setBandLevel(band,
                            (short) (progress + minEqualizer));
                }
            });
            row.addView(minDbTextView);
            row.addView(seekbar);
            row.addView(maxDbTextView);
            mLayout.addView(row);
        }
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        if (isFinishing() && mMediaPlayer != null) {
            mMediaPlayer.release();
            mEqualizer.release();
            mMediaPlayer = null;
        }
    }
}

      这里我采用了手动设置Layout布局的方式,因为上面的Layout采用LinearLayout实现,并且每个SeekBar的属性设置都一样,考虑到SeekBar的数量较多,采用这个方式可能会更好点,至少我们不需要写太繁琐的Layout布局文件。
      撇开那些Layout的布局代码,我们看看最主要的部分:SeekBar和Equalizer的设置。

      android系统提供内置的Equalizer支持,我们可以直接声明并且使用。但必须注意,当我们在代码中使用Equalizer的时候,其实就是调整音量(EQ均衡器是改变音频使得声音发生变化,像是洪亮或者低沉)。所以,我们需要在我们的代码中声明这么一句:

setVolumeControlStream(AudioManager.STREAM_MUSIC);

      因为涉及到硬件方面的修改,我们需要权限:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

      它允许我们进行全局的音频设置。
      我们再来看看这句:

mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());

      每个MediaPlayer都有自己独一无二的SessionId,我们需要将Equalizer附加到这个MediaPlayer上,就必须获取该SessionId。然后我们再创建一个优先级为0的Equalizer对象。所谓的优先级,是因为一个Equalizer engine可以被多个应用程序共享,所以我们必须设置优先级,优先级0代表该应用程序为正常级别。
     要想启动Equalizer,我们还必须这样子:

mEqualizer.setEnabled(true);

    这就是学过单片机的同学非常熟悉的"使能"。

    然后我们再获取支持的频谱:

 short bands = mEqualizer.getNumberOfBands();

    不同的硬件设备支持的频谱是不一样的,像是电脑能支持的频谱就比手机要多得多。
    接着就是获取频谱中的等级范围,我们只需要获取最低和最高即可。

final short minEqualizer = mEqualizer.getBandLevelRange()[0];
final short maxEqualizer = mEqualizer.getBandLevelRange()[1];

     接下来就是遍历频谱,设置SeekBar了:

seekbar.setMax(maxEqualizer - minEqualizer);
seekbar.setProgress(mEqualizer.getBandLevel(band));

seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {}

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {}

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        mEqualizer.setBandLevel(band, (short) (progress + minEqualizer));
    }
});

      我们必须设置SeekBar的最大进度范围,也就是进度顶端所代表的值。接着就是实现SeekBar进度改变时,Equalizer的音频也跟着相应的改变,这就需要监听SeekBar。
      好了,到了这里,基本的EQ均衡器已经实现了,但我们想要的并不是功能的实现,而是界面的实现(这往往是我们这些移动互联网开发者的恶梦,美工设计师们从来都没有考虑过我们要设计出他们的界面有时是多么难甚至不可能的一件事啊!)。

      既然默认的SeekBar样式无法满足我们的要求,我们只能自定义自己想要的SeekBar了。幸好,android还是提供了这种支持:只要继承自AbsSeekBr,我们就能得到自己想要的SeekBar了。

      依然先上源码:

public class VerticalSeekBar extends AbsSeekBar {
    private Drawable mThumb;
    private int height;
    private int width;

    public interface OnSeekBarChangeListener {
        void onProgressChanged(VerticalSeekBar VerticalSeekBar, int progress,
                boolean fromUser);

        void onStartTrackingTouch(VerticalSeekBar VerticalSeekBar);

        void onStopTrackingTouch(VerticalSeekBar VerticalSeekBar);
    }

    private OnSeekBarChangeListener mOnSeekBarChangeListener;

    public VerticalSeekBar(Context context) {
        this(context, null);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.seekBarStyle);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
        mOnSeekBarChangeListener = l;

    }

    void onStartTrackingTouch() {
        if (mOnSeekBarChangeListener != null) {
            mOnSeekBarChangeListener.onStartTrackingTouch(this);
        }
    }

    void onStopTrackingTouch() {
        if (mOnSeekBarChangeListener != null) {
            mOnSeekBarChangeListener.onStopTrackingTouch(this);
        }
    }

    void onProgressRefresh(float scale, boolean fromUser) {
        Drawable thumb = mThumb;
        if (thumb != null) {
            setThumbPos(getHeight(), thumb, scale, Integer.MIN_VALUE);
            invalidate();
        }
        if (mOnSeekBarChangeListener != null) {
            mOnSeekBarChangeListener.onProgressChanged(this, getProgress(),
                    fromUser);
        }
    }

    private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
        int available = w + getPaddingLeft() - getPaddingRight();
        int thumbWidth = thumb.getIntrinsicWidth();
        int thumbHeight = thumb.getIntrinsicHeight();
        available -= thumbWidth;
        available += getThumbOffset() / 2;
        int thumbPos = (int) (scale * available);
        int topBound, bottomBound;
        if (gap == Integer.MIN_VALUE) {
            Rect oldBounds = thumb.getBounds();
            topBound = oldBounds.top;
            bottomBound = oldBounds.bottom;
        } else {
            topBound = gap;
            bottomBound = gap + thumbHeight;
        }
        thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound);
    }

    protected void onDraw(Canvas c) {
        c.rotate(-90);
        c.translate(-height, 0);
        super.onDraw(c);
    }

    protected synchronized void onMeasure(int widthMeasureSpec,
            int heightMeasureSpec) {
        height = View.MeasureSpec.getSize(heightMeasureSpec) / 2;
        width = 50;
        this.setMeasuredDimension(width, height);
    }

    @Override
    public void setThumb(Drawable thumb) {
        mThumb = thumb;
        super.setThumb(thumb);
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldw, oldh);
    }

    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            setPressed(true);
            onStartTrackingTouch();
            trackTouchEvent(event);
            break;

        case MotionEvent.ACTION_MOVE:
            trackTouchEvent(event);
            attemptClaimDrag();
            break;

        case MotionEvent.ACTION_UP:
            trackTouchEvent(event);
            onStopTrackingTouch();
            setPressed(false);
            break;

        case MotionEvent.ACTION_CANCEL:
            onStopTrackingTouch();
            setPressed(false);
            break;
        }
        return true;
    }

    private void trackTouchEvent(MotionEvent event) {
        final int Height = getHeight();
        final int available = Height - getPaddingBottom() - getPaddingTop();
        int Y = (int) event.getY();
        float scale;
        float progress = 0;
        if (Y > Height - getPaddingBottom()) {
            scale = 0.0f;
        } else if (Y < getPaddingTop()) {
            scale = 1.0f;
        } else {
            scale = (float) (Height - getPaddingBottom() - Y)
                    / (float) available;
        }

        final int max = getMax();
        progress = scale * max;

        setProgress((int) progress);
    }

    private void attemptClaimDrag() {
        if (getParent() != null) {
            getParent().requestDisallowInterceptTouchEvent(true);
        }
    }

    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            KeyEvent newEvent = null;
            switch (event.getKeyCode()) {
            case KeyEvent.KEYCODE_DPAD_UP:
                newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
                        KeyEvent.KEYCODE_DPAD_RIGHT);
                break;
            case KeyEvent.KEYCODE_DPAD_DOWN:
                newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
                        KeyEvent.KEYCODE_DPAD_LEFT);
                break;
            case KeyEvent.KEYCODE_DPAD_LEFT:
                newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
                        KeyEvent.KEYCODE_DPAD_DOWN);
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
                        KeyEvent.KEYCODE_DPAD_UP);
                break;
            default:
                newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
                        event.getKeyCode());
                break;
            }
            return newEvent.dispatch(this);
        }
        return false;
    }
}

       代码很长,但关键是我上面标记的几个方法。
       onDraw()该方法就是实现竖直SeekBar的关键。我们可以看到,关键就是那个c.rotate(-90),它实现了我们的竖直:通过反转-90度。setThumbPos()方法是为了调整thumb的大小,这个很重要,尤其是当我们开始排版的时候,thumb很可能因为布局的问题而显示不完全或者根本就不见了。onMeasure()针对的是进度条的设置。至于具体的大小怎样设置,得看大家自己的具体应用了。

       这个是实现的效果:

      android手机上实现竖直seekbar的EQ均衡器

      前面的代码基本保持不变,只要将SeekBar改为VerticalSeekBar就可以了:

for (short i = 0; i < bands; i++) {
            final short band = i;
            int index = (int) i;
            VerticalSeekBar seekBar = (VerticalSeekBar) findViewById(seekBars[index]);
            seekBar.setMax(maxEqualizer - minEqualizer);
            seekBar.setProgress(mEqualizer.getBandLevel(band));

            seekBar.setOnSeekBarChangeListener(new VerticalSeekBar.OnSeekBarChangeListener() {

                @Override
                public void onProgressChanged(VerticalSeekBar VerticalSeekBar,
                        int progress, boolean fromUser) {
                    mEqualizer.setBandLevel(band,
                            (short) (progress + minEqualizer));

                }

                @Override
                public void onStartTrackingTouch(VerticalSeekBar VerticalSeekBar) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onStopTrackingTouch(VerticalSeekBar VerticalSeekBar) {
                    // TODO Auto-generated method stub

                }
            });

       为了实现我上面的布局效果,我这次使用了RelativeLayout布局文件,至于那些间距的调整,就留给读者们了。

      这样的效果还是不行的,因为有个致命的缺陷:android2.3的默认样式和android4.0的默认样式是不一样的!别看我上面的效果挺美观的,在android2.3上可不是这样。

      最好的解决方法就是替换默认样式。

      替换默认样式的方法很简单:在res目录下,新建drawable文件夹,然后我们在该目录下新建一个xml文件:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:id="@android:id/secondaryProgress">
        <clip android:drawable="@drawable/progress2" />
    </item>
    <item android:id="@android:id/progress">
        <clip android:drawable="@drawable/progress1" />
    </item>

</layer-list>

     我们可以使用layer-list来替换默认样式,secondaryProgress指的是我们进度条中剩下的进度,progress指的就是我们当前的进度。
     分别设置好它们的替换图片后,我们再在SeekBar中这样设置:

<com.example.eqpratice.VerticalSeekBar
            android:id="@+id/sec"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/fir"
            android:progressDrawable="@drawable/progress"
            android:secondaryProgress="100"
            android:thumb="@drawable/thumb" />

     这里android: secondaryProgress="100"设置的是我们thumb能达到的最大进度,这个是要设置的,不然会出现thumb超出进度条的情况。
     现在的效果如图:

     android手机上实现竖直seekbar的EQ均衡器

        大家可以根据自己的需要,自定义自己想要的样式。




  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值