Android SeekBar自定义使用图片和颜色显示
来源:互联网 发布:银行理财产品 知乎 编辑:程序博客网 时间:2024/05/22 02:08
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
>
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
>
1
android:progressDrawable="@drawable/seekbar_define_color_style"
由于SeekBar的属性thumb引入了自定义的seekbar_thumb.xml文件,拖动图标是我们自定义的图片:除去这个属性
1
android:thumb="@drawable/seekbar_thumb"
就回复系统默认状态效果最后效果如下:
我们可以通过颜色值再次休息seekbar_thumb.xml文件,使拖动按钮设置成自定义颜色:
----------------------------------------------------------
先是实现默认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()针对的是进度条的设置。至于具体的大小怎样设置,得看大家自己的具体应用了。
这个是实现的效果:
前面的代码基本保持不变,只要将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自定义使用图片和颜色显示
- Android SeekBar自定义使用图片和颜色显示
- Android SeekBar自定义使用图片和颜色显示
- SeekBar自定义(颜色,大小,图片)
- SeekBar自定义(颜色,大小,图片)
- SeekBar自定义和使用
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- Android中自定义SeekBar背景颜色,进度条颜色,滑块图片
- Android中自定义SeekBar的背景颜色,进度条颜色,以及滑块的图片
- 自定义条形ProgressBar和SeekBar的颜色
- android 自定义SeekBar的使用
- Android Seekbar间隔和自定义
- SQLite3数据库加密方案
- android 的启动模式学习以及感悟
- 小数点处理类java
- poj 1141 Brackets Sequence(DP第一弹)
- ServiceConnection
- Android SeekBar自定义使用图片和颜色显示
- mysql问题集整理
- 存储过程
- 创建ZWCAD实体--对齐标注
- HDU 4474 Yet Another Multiple Problem 搜索——BFS
- Oracle ebs-未过账发票-关闭会计期间
- VS2010程序打包操作(超详细的)
- 启动NAT服务报错Error 193:0xc1
- rq06金明的预算方案题解