android中自定義進度條樣式(ProgressDialog)
先發一下系統自帶的進度條和自定義進度條外觀圖片:
圖1
圖2
圖1是系統自帶的進度條,圖2是自定義樣式後的進度條。為了方便只更改進度條外觀,其他的對話方塊屬性及樣式不做修改。
要做到以上效果的修改,需要4個步驟:
1、自定義MyProgressDialog類,雖說是自定義,但實際上是照抄系統自帶的ProgressDialog,只是修改其中的某些寫死了樣式的程式碼。
//包名跟系統的一樣,不能更改 package android.app; import java.text.NumberFormat; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.Spannable; import android.text.SpannableString; import android.text.style.StyleSpan; import android.view.LayoutInflater; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; //資原始檔修改 //import com.android.internal.R; import com.zhao.transfer.R; public class MyProgressDialog extends AlertDialog { /** Creates a ProgressDialog with a circular, spinning progress * bar. This is the default. */ public static final int STYLE_SPINNER = 0; /** Creates a ProgressDialog with a horizontal progress bar. */ public static final int STYLE_HORIZONTAL = 1; private ProgressBar mProgress; private TextView mMessageView; private int mProgressStyle = STYLE_SPINNER; private TextView mProgressNumber; private String mProgressNumberFormat; private TextView mProgressPercent; private NumberFormat mProgressPercentFormat; private int mMax; private int mProgressVal; private int mSecondaryProgressVal; private int mIncrementBy; private int mIncrementSecondaryBy; private Drawable mProgressDrawable; private Drawable mIndeterminateDrawable; private CharSequence mMessage; private boolean mIndeterminate; private boolean mHasStarted; private Handler mViewUpdateHandler; private Context context; public MyProgressDialog(Context context) { super(context); this.context = context; initFormats(); } public MyProgressDialog(Context context, int theme) { super(context, theme); initFormats(); } private void initFormats() { mProgressNumberFormat = "%1d/%2d"; mProgressPercentFormat = NumberFormat.getPercentInstance(); mProgressPercentFormat.setMaximumFractionDigits(0); } public static ProgressDialog show(Context context, CharSequence title, CharSequence message) { return show(context, title, message, false); } public static ProgressDialog show(Context context, CharSequence title, CharSequence message, boolean indeterminate) { return show(context, title, message, indeterminate, false, null); } public static ProgressDialog show(Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable) { return show(context, title, message, indeterminate, cancelable, null); } public static ProgressDialog show(Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable, OnCancelListener cancelListener) { ProgressDialog dialog = new ProgressDialog(context); dialog.setTitle(title); dialog.setMessage(message); dialog.setIndeterminate(indeterminate); dialog.setCancelable(cancelable); dialog.setOnCancelListener(cancelListener); dialog.show(); return dialog; } @Override protected void onCreate(Bundle savedInstanceState) { LayoutInflater inflater = LayoutInflater.from(context); TypedArray a = context.obtainStyledAttributes(null, //此處修改了樣式檔案,引用自定義樣式attrs.xml R.styleable.AlertDialog, R.attr.alertDialogStyle, 0); if (mProgressStyle == STYLE_HORIZONTAL) { /* Use a separate handler to update the text views as they * must be updated on the same thread that created them. */ mViewUpdateHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); /* Update the number and percent */ int progress = mProgress.getProgress(); int max = mProgress.getMax(); if (mProgressNumberFormat != null) { String format = mProgressNumberFormat; mProgressNumber.setText(String.format(format, progress, max)); } else { mProgressNumber.setText(""); } if (mProgressPercentFormat != null) { double percent = (double) progress / (double) max; SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent)); tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mProgressPercent.setText(tmp); } else { mProgressPercent.setText(""); } } }; View view = inflater.inflate(a.getResourceId( //此處修改了樣式檔案,引用自定義樣式 attrs.xml R.styleable.AlertDialog_horizontalProgressLayout, //此處修改了佈局檔案 progress_dialog.xml R.layout.progress_dialog), null); mProgress = (ProgressBar) view.findViewById(R.id.progress); mProgressNumber = (TextView) view.findViewById(R.id.progress_number); mProgressPercent = (TextView) view.findViewById(R.id.progress_percent); setView(view); } else { /*View view = inflater.inflate(a.getResourceId( com.android.internal.R.styleable.AlertDialog_progressLayout, R.layout.progress_dialog), null); mProgress = (ProgressBar) view.findViewById(R.id.progress); mMessageView = (TextView) view.findViewById(R.id.message); setView(view);*/ } a.recycle(); if (mMax > 0) { setMax(mMax); } if (mProgressVal > 0) { setProgress(mProgressVal); } if (mSecondaryProgressVal > 0) { setSecondaryProgress(mSecondaryProgressVal); } if (mIncrementBy > 0) { incrementProgressBy(mIncrementBy); } if (mIncrementSecondaryBy > 0) { incrementSecondaryProgressBy(mIncrementSecondaryBy); } if (mProgressDrawable != null) { setProgressDrawable(mProgressDrawable); } if (mIndeterminateDrawable != null) { setIndeterminateDrawable(mIndeterminateDrawable); } if (mMessage != null) { setMessage(mMessage); } setIndeterminate(mIndeterminate); onProgressChanged(); super.onCreate(savedInstanceState); } @Override public void onStart() { super.onStart(); mHasStarted = true; } @Override protected void onStop() { super.onStop(); mHasStarted = false; } public void setProgress(int value) { if (mHasStarted) { mProgress.setProgress(value); onProgressChanged(); } else { mProgressVal = value; } } public void setSecondaryProgress(int secondaryProgress) { if (mProgress != null) { mProgress.setSecondaryProgress(secondaryProgress); onProgressChanged(); } else { mSecondaryProgressVal = secondaryProgress; } } public int getProgress() { if (mProgress != null) { return mProgress.getProgress(); } return mProgressVal; } public int getSecondaryProgress() { if (mProgress != null) { return mProgress.getSecondaryProgress(); } return mSecondaryProgressVal; } public int getMax() { if (mProgress != null) { return mProgress.getMax(); } return mMax; } public void setMax(int max) { if (mProgress != null) { mProgress.setMax(max); onProgressChanged(); } else { mMax = max; } } public void incrementProgressBy(int diff) { if (mProgress != null) { mProgress.incrementProgressBy(diff); onProgressChanged(); } else { mIncrementBy += diff; } } public void incrementSecondaryProgressBy(int diff) { if (mProgress != null) { mProgress.incrementSecondaryProgressBy(diff); onProgressChanged(); } else { mIncrementSecondaryBy += diff; } } public void setProgressDrawable(Drawable d) { if (mProgress != null) { mProgress.setProgressDrawable(d); } else { mProgressDrawable = d; } } public void setIndeterminateDrawable(Drawable d) { if (mProgress != null) { mProgress.setIndeterminateDrawable(d); } else { mIndeterminateDrawable = d; } } public void setIndeterminate(boolean indeterminate) { if (mProgress != null) { mProgress.setIndeterminate(indeterminate); } else { mIndeterminate = indeterminate; } } public boolean isIndeterminate() { if (mProgress != null) { return mProgress.isIndeterminate(); } return mIndeterminate; } @Override public void setMessage(CharSequence message) { if (mProgress != null) { if (mProgressStyle == STYLE_HORIZONTAL) { super.setMessage(message); } else { mMessageView.setText(message); } } else { mMessage = message; } } public void setProgressStyle(int style) { mProgressStyle = style; } /** * Change the format of the small text showing current and maximum units * of progress. The default is "%1d/%2d". * Should not be called during the number is progressing. * @param format A string passed to {@link String#format String.format()}; * use "%1d" for the current number and "%2d" for the maximum. If null, * nothing will be shown. */ public void setProgressNumberFormat(String format) { mProgressNumberFormat = format; onProgressChanged(); } /** * Change the format of the small text showing the percentage of progress. * The default is * {@link NumberFormat#getPercentInstance() NumberFormat.getPercentageInstnace().} * Should not be called during the number is progressing. * @param format An instance of a {@link NumberFormat} to generate the * percentage text. If null, nothing will be shown. */ public void setProgressPercentFormat(NumberFormat format) { mProgressPercentFormat = format; onProgressChanged(); } private void onProgressChanged() { if (mProgressStyle == STYLE_HORIZONTAL) { if (mViewUpdateHandler != null && !mViewUpdateHandler.hasMessages(0)) { mViewUpdateHandler.sendEmptyMessage(0); } } } }
2、自定義ProgressDialog的佈局檔案(progress_dialog.xml),為了方便照抄系統自帶的就行了,只是修改進度條style屬性:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="match_parent"> <!-- style=修改成自定義的樣式 --> <ProgressBar android:id="@+id/progress" style="@style/my_progress_style" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dip" android:layout_marginBottom="5dip" android:layout_marginStart="10dip" android:layout_marginEnd="10dip" android:layout_centerHorizontal="true" /> <TextView android:id="@+id/progress_percent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="12dip" android:layout_marginStart="10dip" android:layout_marginEnd="10dip" android:layout_alignParentLeft="true" android:layout_below="@id/progress" android:textColor="#fff" /> <TextView android:id="@+id/progress_number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="12dip" android:layout_marginStart="10dip" android:layout_marginEnd="10dip" android:layout_alignParentRight="true" android:layout_below="@id/progress" android:textColor="#fff" /> </RelativeLayout>
3、自定義ProgressDialog的樣式,需要在兩個檔案中新增內容attrs.xml 和 styles.xml:
attrs.xml檔案新增如下內容:
<attr name="alertDialogStyle" format="reference" /> <!-- The set of attributes that describe a AlertDialog's theme. --> <declare-styleable name="AlertDialog"> <attr name="fullDark" format="reference|color" /> <attr name="topDark" format="reference|color" /> <attr name="centerDark" format="reference|color" /> <attr name="bottomDark" format="reference|color" /> <attr name="fullBright" format="reference|color" /> <attr name="topBright" format="reference|color" /> <attr name="centerBright" format="reference|color" /> <attr name="bottomBright" format="reference|color" /> <attr name="bottomMedium" format="reference|color" /> <attr name="centerMedium" format="reference|color" /> <attr name="progressLayout" format="reference|color" /> <attr name="horizontalProgressLayout" format="reference|color" /> </declare-styleable>
styles.xml檔案中新增如下內容:
<style name="my_progress_style" parent="android:Widget.ProgressBar.Horizontal">
<item name="android:indeterminateOnly" >false</item>
<item name="android:progressDrawable">@drawable/progress_layer_list</item>
<item name="android:minHeight">5dp</item>
<item name="android:maxHeight">5dp</item>
</style>
<style name="AlertDialog">
<item name="progressLayout">@layout/progress_dialog</item>
<item name="horizontalProgressLayout">@layout/progress_dialog</item>
</style>
4、自定義進度條的drawable(progress_layer_list.xml),檔案內容如下:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@android:id/background" >
<shape android:shape="rectangle">
<corners android:radius="5dp"></corners>
<gradient android:startColor="#ddd" android:centerColor="#ddd" android:endColor="#ddd"
android:type="linear" android:angle="270" android:centerY="0.6" ></gradient>
</shape>
</item>
<item android:id="@android:id/progress" >
<clip >
<shape android:shape="rectangle">
<corners android:radius="5dp" ></corners>
<gradient android:startColor="#ff0" android:centerColor="#aaa" android:endColor="#0ff"
android:type="linear" android:angle="270" android:centerY="0.6" />
</shape>
</clip>
</item>
<item android:id="@android:id/secondaryProgress" >
<clip >
<shape android:shape="rectangle" >
<corners android:radius="5dp" ></corners>
<gradient android:startColor="#00f" android:centerColor="#fff" android:endColor="#0dd"
android:type="linear" android:angle="270" android:centerY="0.6" />
</shape>
</clip>
</item>
</layer-list>
經以上修改後,就可以使用自定義的進度對話方塊了,跟使用系統自帶的一樣,並沒有什麼差別。
MyProgressDialog progress = null;
.....
if (progress == null) {
progress = new MyProgressDialog(this);
progress.setTitle(“檔案接收進度”);
progress.setIcon(android.R.drawable.ic_popup_sync);
progress.setMessage(“張國榮,許冠傑--沉默是金.mp3”);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setProgress(cur);
progress.setMax(100);
progress.show();
} else if (progress != null) {
progress.setMessage(msg);
progress.setProgress(cur);
}