Android Progress Dialog For Material Design (Android L).
Create New Project In Android Eclips.
—> AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.materialprogressdailogdesign" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
—> activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <ScrollView 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" android:fillViewport="true" android:scrollbarStyle="outsideOverlay"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="@dimen/title_text" android:padding="8dp" android:textColor="#FF000000" android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" android:text="Circular"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="horizontal" android:weightSum="2.0" android:baselineAligned="false"> <FrameLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1.0"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_circular" android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="true" app:pv_progressStyle="@style/CircularProgressDrawableStyle" app:pv_progressMode="indeterminate"/> </FrameLayout> <FrameLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1.0"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_circular_colors" android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="true" app:pv_progressStyle="@style/ColorsCircularProgressDrawableStyle" app:pv_progressMode="indeterminate"/> </FrameLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="horizontal" android:weightSum="2.0" android:baselineAligned="false"> <FrameLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1.0"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_circular_inout" android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="true" app:pv_progressStyle="@style/InOutCircularProgressDrawableStyle" app:pv_progressMode="indeterminate"/> </FrameLayout> <FrameLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1.0"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_circular_inout_colors" android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="true" app:pv_progressStyle="@style/InOutColorsCircularProgressDrawableStyle" app:pv_progressMode="indeterminate"/> </FrameLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="horizontal" android:weightSum="2.0" android:baselineAligned="false"> <FrameLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1.0"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_circular_determinate_in_out" android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="true" app:pv_progressStyle="@style/DeterminateInOutCircularProgressDrawableStyle" app:pv_progressMode="determinate"/> </FrameLayout> <FrameLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1.0"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_circular_determinate" android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="true" app:pv_progressStyle="@style/DeterminateCircularProgressDrawableStyle" app:pv_progressMode="determinate"/> </FrameLayout> </LinearLayout> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="@dimen/title_text" android:padding="8dp" android:textColor="#FF000000" android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" android:text="Linear"/> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_linear" android:layout_width="match_parent" android:layout_height="4dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="false" app:pv_progressStyle="@style/LinearProgressDrawableStyle" app:pv_progressMode="indeterminate"/> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_linear_colors" android:layout_width="match_parent" android:layout_height="4dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="false" app:pv_progressStyle="@style/ColorsLinearProgressDrawableStyle" app:pv_progressMode="indeterminate"/> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_linear_determinate" android:layout_width="match_parent" android:layout_height="4dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="false" app:pv_progressStyle="@style/DeterminateLinearProgressDrawableStyle" app:pv_progressMode="determinate"/> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_linear_query" android:layout_width="match_parent" android:layout_height="4dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="false" app:pv_progressStyle="@style/QueryLinearProgressDrawableStyle" app:pv_progressMode="query"/> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <com.example.material.widget.ProgressView android:id="@+id/progress_pv_linear_buffer" android:layout_width="match_parent" android:layout_height="4dp" android:layout_gravity="center" app:pv_autostart = "false" app:pv_circular="false" app:pv_progressStyle="@style/BufferLinearProgressDrawableStyle" app:pv_progressMode="buffer"/> </FrameLayout> </LinearLayout> </ScrollView>
—-> Values Folder
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="WeekView"> <attr name="wv_backgroundColor" format="reference|color"/> <attr name="wv_verticalPadding" format="reference|dimension"/> <attr name="wv_horizontalPadding" format="reference|dimension"/> <attr name="wv_animDuration" format="reference|integer"/> </declare-styleable> <declare-styleable name="ContactView"> <attr name="cv_buttonSrc" format="reference"/> <attr name="cv_buttonSize" format="reference|dimension"/> <attr name="cv_avatarSrc" format="reference"/> <attr name="cv_avatarSize" format="reference|dimension"/> <attr name="cv_spacing" format="reference|dimension"/> <attr name="cv_name" format="reference|string"/> <attr name="cv_nameTextAppearance" format="reference"/> <attr name="cv_nameTextSize" format="reference|dimension"/> <attr name="cv_nameTextColor" format="reference|color"/> <attr name="cv_address" format="reference|string"/> <attr name="cv_addressTextAppearance" format="reference"/> <attr name="cv_addressTextSize" format="reference|dimension"/> <attr name="cv_addressTextColor" format="reference|color"/> <attr name="android:minHeight" /> </declare-styleable> <declare-styleable name="ContactEditText"> <attr name="cet_spanHeight" format="reference|dimension"/> <attr name="cet_spanMaxWidth" format="reference|dimension"/> <attr name="cet_spanPaddingLeft" format="reference|dimension"/> <attr name="cet_spanPaddingRight" format="reference|dimension"/> <attr name="cet_spanFontFamily" format="reference|string"/> <attr name="cet_spanTextStyle" format="integer"> <enum name="normal" value="0" /> <enum name="bold" value="1" /> <enum name="italic" value="2" /> <enum name="bold_italic" value="3" /> </attr> <attr name="cet_spanTextSize" format="reference|dimension"/> <attr name="cet_spanTextColor" format="reference|color"/> <attr name="cet_spanBackgroundColor" format="reference|color"/> <attr name="cet_spanSpacing" format="reference|dimension"/> </declare-styleable> <attr name="pv_progressMode" format="integer"> <enum name="determinate" value="0x00000000" /> <enum name="indeterminate" value="0x00000001" /> <enum name="buffer" value="0x00000002" /> <enum name="query" value="0x00000003" /> </attr> <attr name="pv_progress" format="float"/> <attr name="pv_secondaryProgress" format="float"/> <attr name="rd_style" format="reference"/> <attr name="rd_enable" format="boolean"/> <declare-styleable name="CircularProgressDrawable"> <attr name="cpd_padding" format="reference|dimension"/> <attr name="cpd_initialAngle" format="reference|integer"/> <attr name="cpd_maxSweepAngle" format="reference|integer"/> <attr name="cpd_minSweepAngle" format="reference|integer"/> <attr name="cpd_strokeSize" format="reference|dimension"/> <attr name="cpd_strokeColor" format="reference|color"/> <attr name="cpd_strokeSecondaryColor" format="reference|color"/> <attr name="cpd_strokeColors" format="reference"/> <attr name="cpd_reverse" format="boolean"/> <attr name="cpd_rotateDuration" format="reference|integer"/> <attr name="cpd_transformDuration" format="reference|integer"/> <attr name="cpd_keepDuration" format="reference|integer"/> <attr name="cpd_transformInterpolator" format="reference"/> <attr name="cpd_inAnimDuration" format="reference|integer"/> <attr name="cpd_outAnimDuration" format="reference|integer"/> <attr name="cpd_inStepColors" format="reference"/> <attr name="cpd_inStepPercent" format="float"/> <attr name="pv_progressMode"/> <attr name="pv_progress"/> <attr name="pv_secondaryProgress"/> </declare-styleable> <declare-styleable name="LinearProgressDrawable"> <attr name="lpd_maxLineWidth" format="reference|dimension|fraction"/> <attr name="lpd_minLineWidth" format="reference|dimension|fraction"/> <attr name="lpd_strokeSize" format="reference|dimension"/> <attr name="lpd_strokeColor" format="reference|color"/> <attr name="lpd_strokeSecondaryColor" format="reference|color"/> <attr name="lpd_strokeColors" format="reference"/> <attr name="lpd_reverse" format="boolean"/> <attr name="lpd_travelDuration" format="reference|integer"/> <attr name="lpd_transformDuration" format="reference|integer"/> <attr name="lpd_keepDuration" format="reference|integer"/> <attr name="lpd_transformInterpolator" format="reference"/> <attr name="lpd_inAnimDuration" format="reference|integer"/> <attr name="lpd_outAnimDuration" format="reference|integer"/> <attr name="lpd_verticalAlign" format="integer"> <enum name="top" value="0x00000000" /> <enum name="center" value="0x00000001" /> <enum name="bottom" value="0x00000002" /> </attr> <attr name="pv_progressMode"/> <attr name="pv_progress"/> <attr name="pv_secondaryProgress"/> </declare-styleable> <declare-styleable name="ProgressView"> <attr name="pv_autostart" format="boolean"/> <attr name="pv_circular" format="boolean"/> <attr name="pv_progressStyle" format="reference"/> </declare-styleable> <declare-styleable name="RippleView"> <attr name="rd_style" /> <attr name="rd_enable" /> </declare-styleable> <declare-styleable name="RippleDrawable"> <attr name="rd_backgroundColor" format="reference|color"/> <attr name="rd_backgroundAnimDuration" format="reference|integer"/> <attr name="rd_maxRippleRadius" format="reference|dimension|integer"> <enum name="match_view" value="0x00000000" /> </attr> <attr name="rd_rippleColor" format="reference|color"/> <attr name="rd_rippleAnimDuration" format="reference|integer"/> <attr name="rd_inInterpolator" format="reference"/> <attr name="rd_outInterpolator" format="reference"/> <attr name="rd_maskType" format="integer"> <enum name="rectangle" value="0x00000000" /> <enum name="oval" value="0x00000001" /> </attr> <attr name="rd_rippleType" format="integer"> <enum name="touch" value="0x00000000" /> <enum name="wave" value="0x00000001" /> </attr> <attr name="rd_cornerRadius" format="reference|dimension"/> <attr name="rd_topLeftCornerRadius" format="reference|dimension"/> <attr name="rd_topRightCornerRadius" format="reference|dimension"/> <attr name="rd_bottomLeftCornerRadius" format="reference|dimension"/> <attr name="rd_bottomRightCornerRadius" format="reference|dimension"/> <attr name="rd_padding" format="reference|dimension"/> <attr name="rd_leftPadding" format="reference|dimension"/> <attr name="rd_topPadding" format="reference|dimension"/> <attr name="rd_rightPadding" format="reference|dimension"/> <attr name="rd_bottomPadding" format="reference|dimension"/> <attr name="rd_delayClick" format="boolean"/> </declare-styleable> <declare-styleable name="LineMorphingDrawable"> <attr name="lmd_state" format="reference"/> <attr name="lmd_curState" format="integer"/> <attr name="lmd_padding" format="reference|dimension"/> <attr name="lmd_paddingLeft" format="reference|dimension"/> <attr name="lmd_paddingTop" format="reference|dimension"/> <attr name="lmd_paddingRight" format="reference|dimension"/> <attr name="lmd_paddingBottom" format="reference|dimension"/> <attr name="lmd_animDuration" format="reference|integer"/> <attr name="lmd_interpolator" format="reference"/> <attr name="lmd_strokeSize" format="reference|dimension"/> <attr name="lmd_strokeColor" format="reference|color"/> <attr name="lmd_strokeCap" format="integer"> <enum name="butt" value="0x00000000" /> <enum name="round" value="0x00000001" /> <enum name="square" value="0x00000002" /> </attr> <attr name="lmd_strokeJoin" format="integer"> <enum name="miter" value="0x00000000" /> <enum name="round" value="0x00000001" /> <enum name="bevel" value="0x00000002" /> </attr> <attr name="lmd_clockwise" format="boolean"/> </declare-styleable> <declare-styleable name="RadioButtonDrawable"> <attr name="rbd_width" format="reference|dimension"/> <attr name="rbd_height" format="reference|dimension"/> <attr name="rbd_strokeSize" format="reference|dimension"/> <attr name="rbd_radius" format="reference|dimension"/> <attr name="rbd_innerRadius" format="reference|dimension"/> <attr name="rbd_strokeColor" format="reference|color"/> <attr name="rbd_animDuration" format="reference|integer"/> </declare-styleable> <declare-styleable name="CheckBoxDrawable"> <attr name="cbd_width" format="reference|dimension"/> <attr name="cbd_height" format="reference|dimension"/> <attr name="cbd_boxSize" format="reference|dimension"/> <attr name="cbd_cornerRadius" format="reference|dimension"/> <attr name="cbd_strokeSize" format="reference|dimension"/> <attr name="cbd_strokeColor" format="reference|color"/> <attr name="cbd_tickColor" format="reference|color"/> <attr name="cbd_animDuration" format="reference|integer"/> </declare-styleable> <declare-styleable name="Switch"> <attr name="sw_trackSize" format="reference|dimension"/> <attr name="sw_trackColor" format="reference|color"/> <attr name="sw_trackCap" format="integer"> <enum name="butt" value="0x00000000" /> <enum name="round" value="0x00000001" /> <enum name="square" value="0x00000002" /> </attr> <attr name="sw_thumbColor" format="reference|color"/> <attr name="sw_thumbRadius" format="reference|dimension"/> <attr name="sw_thumbElevation" format="reference|dimension"/> <attr name="sw_animDuration" format="reference|integer"/> <attr name="sw_interpolator" format="reference"/> <attr name="android:gravity" /> <attr name="android:checked" /> </declare-styleable> <declare-styleable name="Slider"> <attr name="sl_trackSize" format="reference|dimension"/> <attr name="sl_primaryColor" format="reference|color"/> <attr name="sl_secondaryColor" format="reference|color"/> <attr name="sl_trackCap" format="integer"> <enum name="butt" value="0x00000000" /> <enum name="round" value="0x00000001" /> <enum name="square" value="0x00000002" /> </attr> <attr name="sl_thumbBorderSize" format="reference|dimension"/> <attr name="sl_thumbRadius" format="reference|dimension"/> <attr name="sl_thumbFocusRadius" format="reference|dimension"/> <attr name="sl_travelAnimDuration" format="reference|integer"/> <attr name="sl_transformAnimDuration" format="reference|integer"/> <attr name="sl_interpolator" format="reference"/> <attr name="sl_minValue" format="reference|integer"/> <attr name="sl_maxValue" format="reference|integer"/> <attr name="sl_stepValue" format="reference|integer"/> <attr name="sl_value" format="reference|integer"/> <attr name="sl_discreteMode" format="reference|boolean"/> <attr name="sl_fontFamily" format="string|reference"/> <attr name="sl_textStyle" format="integer"> <enum name="normal" value="0" /> <enum name="bold" value="1" /> <enum name="italic" value="2" /> <enum name="bold_italic" value="3" /> </attr> <attr name="sl_textSize" format="reference|dimension"/> <attr name="sl_textColor" format="reference|color"/> <attr name="android:gravity" /> <attr name="android:enabled" /> </declare-styleable> <declare-styleable name="NavigationDrawerDrawable"> <attr name="nd_ripple" format="reference"/> <attr name="nd_icon" format="reference"/> </declare-styleable> <declare-styleable name="TabPageIndicator"> <attr name="tpi_tabPadding" format="reference|dimension"/> <attr name="tpi_tabRipple" format="reference"/> <attr name="tpi_indicatorColor" format="reference|color"/> <attr name="tpi_indicatorHeight" format="reference|dimension"/> <attr name="android:textAppearance" /> <attr name="tpi_mode" format="integer"> <enum name="scroll" value="0x00000000" /> <enum name="fixed" value="0x00000001" /> </attr> </declare-styleable> <declare-styleable name="EditText"> <attr name="et_inputId" format="reference"/> <attr name="et_labelEnable" format="boolean"/> <attr name="et_labelPadding" format="reference|dimension"/> <attr name="et_labelTextSize" format="reference|dimension"/> <attr name="et_labelTextColor" format="reference|color"/> <attr name="et_labelTextAppearance" format="reference"/> <attr name="et_labelEllipsize" format="integer"> <enum name="start" value="0x00000001" /> <enum name="middle" value="0x00000002" /> <enum name="end" value="0x00000003" /> <enum name="marquee" value="0x00000004" /> </attr> <attr name="et_labelInAnim" format="reference"/> <attr name="et_labelOutAnim" format="reference"/> <attr name="et_supportMode" format="integer"> <enum name="none" value="0x00000000" /> <enum name="helper" value="0x00000001" /> <enum name="helperWithError" value="0x00000002" /> <enum name="charCounter" value="0x00000003" /> </attr> <attr name="et_supportMaxChars" format="reference|integer"/> <attr name="et_helper" format="reference|string"/> <attr name="et_error" format="reference|string"/> <attr name="et_supportPadding" format="reference|dimension"/> <attr name="et_supportTextSize" format="reference|dimension"/> <attr name="et_supportTextColor" format="reference|color"/> <attr name="et_supportTextErrorColor" format="reference|color"/> <attr name="et_supportTextAppearance" format="reference"/> <attr name="et_supportSingleLine" format="boolean"/> <attr name="et_supportMaxLines" format="reference|integer"/> <attr name="et_supportLines" format="reference|integer"/> <attr name="et_supportEllipsize" format="integer"> <enum name="start" value="0x00000001" /> <enum name="middle" value="0x00000002" /> <enum name="end" value="0x00000003" /> <enum name="marquee" value="0x00000004" /> </attr> <attr name="et_dividerColor" format="reference|color"/> <attr name="et_dividerErrorColor" format="reference|color"/> <attr name="et_dividerHeight" format="reference|dimension"/> <attr name="et_dividerPadding" format="reference|dimension"/> <attr name="et_dividerAnimDuration" format="reference|integer"/> <attr name="et_dividerCompoundPadding" format="boolean"/> <attr name="et_autoCompleteMode" format="integer"> <enum name="none" value="0"/> <enum name="single" value="1"/> <enum name="multi" value="2"/> </attr> </declare-styleable> <declare-styleable name="SnackBar"> <attr name="sb_backgroundColor" format="reference|color"/> <attr name="sb_backgroundCornerRadius" format="reference|dimension"/> <attr name="sb_horizontalPadding" format="reference|dimension"/> <attr name="sb_verticalPadding" format="reference|dimension"/> <attr name="sb_width" format="reference|dimension|integer"> <enum name="match_parent" value="-1" /> <enum name="wrap_content" value="-2" /> </attr> <attr name="sb_minWidth" format="reference|dimension"/> <attr name="sb_maxWidth" format="reference|dimension"/> <attr name="sb_height" format="reference|dimension|integer"> <enum name="match_parent" value="-1" /> <enum name="wrap_content" value="-2" /> </attr> <attr name="sb_minHeight" format="reference|dimension"/> <attr name="sb_maxHeight" format="reference|dimension"/> <attr name="sb_marginLeft" format="reference|dimension"/> <attr name="sb_marginBottom" format="reference|dimension"/> <attr name="sb_textSize" format="reference|dimension"/> <attr name="sb_textColor" format="reference|color"/> <attr name="sb_textAppearance" format="reference"/> <attr name="sb_text" format="reference|string"/> <attr name="sb_singleLine" format="boolean"/> <attr name="sb_maxLines" format="reference|integer"/> <attr name="sb_lines" format="reference|integer"/> <attr name="sb_ellipsize" format="integer"> <enum name="start" value="0x00000001" /> <enum name="middle" value="0x00000002" /> <enum name="end" value="0x00000003" /> <enum name="marquee" value="0x00000004" /> </attr> <attr name="sb_actionTextSize" format="reference|dimension"/> <attr name="sb_actionTextColor" format="reference|color"/> <attr name="sb_actionTextAppearance" format="reference"/> <attr name="sb_actionText" format="reference|string"/> <attr name="sb_actionRipple" format="reference"/> <attr name="sb_duration" format="reference|integer"/> <attr name="sb_inAnimation" format="reference"/> <attr name="sb_outAnimation" format="reference"/> <attr name="sb_removeOnDismiss" format="boolean" /> </declare-styleable> <declare-styleable name="FloatingActionButton"> <attr name="fab_backgroundColor" format="reference|color"/> <attr name="fab_radius" format="reference|dimension"/> <attr name="fab_elevation" format="reference|dimension"/> <attr name="fab_iconSrc" format="reference"/> <attr name="fab_iconLineMorphing" format="reference"/> <attr name="fab_iconSize" format="reference|dimension"/> <attr name="fab_interpolator" format="reference"/> <attr name="fab_animDuration" format="reference|integer"/> </declare-styleable> <declare-styleable name="Spinner"> <attr name="android:dropDownWidth" /> <attr name="android:popupBackground" /> <attr name="android:minWidth"/> <attr name="android:minHeight"/> <attr name="spn_labelEnable" format="boolean"/> <attr name="spn_labelPadding" format="reference|dimension"/> <attr name="spn_labelTextSize" format="reference|dimension"/> <attr name="spn_labelTextColor" format="reference|color"/> <attr name="spn_labelTextAppearance" format="reference"/> <attr name="spn_labelEllipsize" format="integer"> <enum name="start" value="0x00000001" /> <enum name="middle" value="0x00000002" /> <enum name="end" value="0x00000003" /> <enum name="marquee" value="0x00000004" /> </attr> <attr name="spn_label" format="string|reference"/> <attr name="spn_popupItemAnimation" format="reference"/> <attr name="spn_popupItemAnimOffset" format="integer"/> <attr name="spn_arrowColor" format="reference|color"/> <attr name="spn_arrowSize" format="reference|dimension"/> <attr name="spn_arrowPadding" format="reference|dimension"/> <attr name="spn_arrowAnimDuration" format="integer"/> <attr name="spn_arrowInterpolator" format="reference"/> <attr name="spn_arrowAnimClockwise" format="boolean"/> <attr name="spn_arrowSwitchMode" format="boolean"/> <attr name="spn_dividerColor" format="reference|color"/> <attr name="spn_dividerHeight" format="reference|dimension"/> <attr name="spn_dividerPadding" format="reference|dimension"/> <attr name="spn_dividerAnimDuration" format="reference|integer"/> </declare-styleable> <declare-styleable name="Dialog"> <attr name="android:layout_width" /> <attr name="android:layout_height" /> <attr name="di_dimAmount" format="float" /> <attr name="di_backgroundColor" format="color|reference" /> <attr name="di_elevation" format="dimension|reference" /> <attr name="di_maxElevation" format="dimension|reference" /> <attr name="di_cornerRadius" format="dimension|reference" /> <attr name="di_titleTextAppearance" format="reference" /> <attr name="di_titleTextColor" format="color|reference" /> <attr name="di_actionBackground" format="reference" /> <attr name="di_actionRipple" format="reference" /> <attr name="di_actionTextAppearance" format="reference" /> <attr name="di_actionTextColor" format="color|reference" /> <attr name="di_positiveActionBackground" format="reference" /> <attr name="di_positiveActionRipple" format="reference" /> <attr name="di_positiveActionTextAppearance" format="reference" /> <attr name="di_positiveActionTextColor" format="color|reference" /> <attr name="di_negativeActionBackground" format="reference" /> <attr name="di_negativeActionRipple" format="reference" /> <attr name="di_negativeActionTextAppearance" format="reference" /> <attr name="di_negativeActionTextColor" format="color|reference" /> <attr name="di_neutralActionBackground" format="reference" /> <attr name="di_neutralActionRipple" format="reference" /> <attr name="di_neutralActionTextAppearance" format="reference" /> <attr name="di_neutralActionTextColor" format="color|reference" /> <attr name="di_dividerColor" format="color|reference" /> <attr name="di_dividerHeight" format="dimension|reference" /> <attr name="di_inAnimation" format="reference" /> <attr name="di_outAnimation" format="reference" /> <attr name="di_cancelable" format="boolean" /> <attr name="di_canceledOnTouchOutside" format="boolean" /> </declare-styleable> <declare-styleable name="SimpleDialog"> <attr name="di_messageTextAppearance" format="reference" /> <attr name="di_messageTextColor" format="color|reference" /> <attr name="di_radioButtonStyle" format="reference" /> <attr name="di_checkBoxStyle" format="reference" /> <attr name="di_itemHeight" format="dimension|reference" /> <attr name="di_itemTextAppearance" format="reference" /> </declare-styleable> <declare-styleable name="TimePicker"> <attr name="tp_backgroundColor" format="color|reference" /> <attr name="tp_selectionColor" format="color|reference" /> <attr name="tp_selectionRadius" format="dimension|reference" /> <attr name="tp_tickSize" format="dimension|reference" /> <attr name="tp_fontFamily" format="string|reference"/> <attr name="tp_textStyle" format="integer"> <enum name="normal" value="0" /> <enum name="bold" value="1" /> <enum name="italic" value="2" /> <enum name="bold_italic" value="3" /> </attr> <attr name="tp_textSize" format="dimension|reference" /> <attr name="tp_textColor" format="color|reference" /> <attr name="tp_textHighlightColor" format="color|reference" /> <attr name="tp_animDuration" format="integer|reference" /> <attr name="tp_inInterpolator" format="reference" /> <attr name="tp_outInterpolator" format="reference" /> <attr name="tp_mode" format="integer"> <enum name="hour" value="0" /> <enum name="minute" value="1" /> </attr> <attr name="tp_24Hour" format="boolean"/> <attr name="tp_hour" format="integer"/> <attr name="tp_minute" format="integer"/> </declare-styleable> <declare-styleable name="TimePickerDialog"> <attr name="tp_headerHeight" format="dimension|reference" /> <attr name="tp_textTimeColor" format="color|reference" /> <attr name="tp_textTimeSize" format="dimension|reference" /> <attr name="tp_am" format="string|reference"/> <attr name="tp_pm" format="string|reference"/> </declare-styleable> <attr name="dp_textHighlightColor" format="color|reference" /> <attr name="dp_textColor" format="color|reference" /> <attr name="dp_selectionColor" format="color|reference" /> <attr name="dp_animDuration" format="integer|reference" /> <attr name="dp_inInterpolator" format="reference" /> <attr name="dp_outInterpolator" format="reference" /> <attr name="dp_yearMin" format="integer"/> <attr name="dp_monthMin" format="integer"/> <attr name="dp_dayMin" format="integer"/> <attr name="dp_yearMax" format="integer"/> <attr name="dp_monthMax" format="integer"/> <attr name="dp_dayMax" format="integer"/> <attr name="dp_year" format="integer"/> <attr name="dp_month" format="integer"/> <attr name="dp_day" format="integer"/> <attr name="dp_fontFamily" format="string|reference"/> <attr name="dp_textStyle" format="integer"> <enum name="normal" value="0" /> <enum name="bold" value="1" /> <enum name="italic" value="2" /> <enum name="bold_italic" value="3" /> </attr> <declare-styleable name="YearPicker"> <attr name="dp_yearMin" /> <attr name="dp_yearMax" /> <attr name="dp_year" /> <attr name="dp_yearTextSize" format="dimension|reference" /> <attr name="dp_yearItemHeight" format="dimension|reference" /> <attr name="dp_textHighlightColor" /> <attr name="dp_textColor" /> <attr name="dp_selectionColor" /> <attr name="dp_animDuration" /> <attr name="dp_inInterpolator" /> <attr name="dp_outInterpolator" /> <attr name="dp_fontFamily" /> <attr name="dp_textStyle" /> </declare-styleable> <declare-styleable name="DatePicker"> <attr name="dp_yearMin" /> <attr name="dp_monthMin" /> <attr name="dp_dayMin" /> <attr name="dp_yearMax" /> <attr name="dp_monthMax" /> <attr name="dp_dayMax" /> <attr name="dp_year" /> <attr name="dp_month" /> <attr name="dp_day" /> <attr name="dp_dayTextSize" format="dimension|reference" /> <attr name="dp_textLabelColor" format="color|reference" /> <attr name="dp_textDisableColor" format="color|reference" /> <attr name="dp_textHighlightColor" /> <attr name="dp_textColor" /> <attr name="dp_selectionColor" /> <attr name="dp_animDuration" /> <attr name="dp_inInterpolator" /> <attr name="dp_outInterpolator" /> <attr name="dp_fontFamily" /> <attr name="dp_textStyle" /> <attr name="android:padding" /> <attr name="android:paddingLeft" /> <attr name="android:paddingTop" /> <attr name="android:paddingRight" /> <attr name="android:paddingBottom" /> </declare-styleable> <declare-styleable name="DatePickerDialog"> <attr name="dp_headerPrimaryHeight" format="dimension|reference" /> <attr name="dp_headerPrimaryColor" format="color|reference" /> <attr name="dp_headerSecondaryHeight" format="dimension|reference" /> <attr name="dp_headerSecondaryColor" format="color|reference" /> <attr name="dp_headerPrimaryTextSize" format="dimension|reference" /> <attr name="dp_headerSecondaryTextSize" format="dimension|reference" /> <attr name="dp_textHeaderColor" format="color|reference" /> </declare-styleable> </resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <array name="progress_colors"> <item>#FF3F8AF8</item> <item>#FFD8433C</item> <item>#FFF2AF3A</item> <item>#FF279B5E</item> </array> <array name="in_colors"> <item>#FFB5D4FF</item> <item>#FFDEEAFC</item> <item>#FFFAFFFE</item> </array> </resources>
dimens.xml
<resources> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <dimen name="title_text">16sp</dimen> </resources>
styles.xml
<resources> <!-- Base application theme, dependent on API level. This theme is replaced by AppBaseTheme from res/values-vXX/styles.xml on newer devices. --> <style name="AppBaseTheme" parent="Theme.AppCompat.Light"> <!-- Theme customizations available in newer API levels can go in res/values-vXX/styles.xml, while customizations related to backward-compatibility can go here. --> </style> <!-- Application theme. --> <style name="AppTheme" parent="AppBaseTheme"> <!-- All customizations that are NOT specific to a particular API-level can go here. --> </style> <!-- Progress Style --> <style name="CircularProgressDrawableStyle" parent="Material.Drawable.CircularProgress"/> <style name="ColorsCircularProgressDrawableStyle" parent="Material.Drawable.CircularProgress"> <item name="cpd_strokeColors">@array/progress_colors</item> </style> <style name="InOutCircularProgressDrawableStyle" parent="Material.Drawable.CircularProgress"> <item name="cpd_inAnimDuration">800</item> <item name="cpd_inStepPercent">0.5</item> <item name="cpd_inStepColors">@array/in_colors</item> <item name="cpd_outAnimDuration">400</item> </style> <style name="InOutColorsCircularProgressDrawableStyle" parent="Material.Drawable.CircularProgress"> <item name="cpd_inAnimDuration">800</item> <item name="cpd_inStepPercent">0.5</item> <item name="cpd_inStepColors">@array/in_colors</item> <item name="cpd_outAnimDuration">400</item> <item name="cpd_strokeColors">@array/progress_colors</item> </style> <style name="DeterminateInOutCircularProgressDrawableStyle" parent="Material.Drawable.CircularProgress.Determinate"> <item name="cpd_inAnimDuration">400</item> <item name="cpd_outAnimDuration">400</item> <item name="cpd_initialAngle">-90</item> </style> <style name="DeterminateCircularProgressDrawableStyle" parent="Material.Drawable.CircularProgress.Determinate"> <item name="cpd_inAnimDuration">0</item> <item name="cpd_outAnimDuration">0</item> <item name="cpd_initialAngle">-90</item> </style> <style name="LinearProgressDrawableStyle" parent="Material.Drawable.LinearProgress"> <item name="lpd_strokeSecondaryColor">#00000000</item> </style> <style name="ColorsLinearProgressDrawableStyle" parent="Material.Drawable.LinearProgress"> <item name="lpd_strokeColors">@array/progress_colors</item> <item name="lpd_strokeSecondaryColor">#00000000</item> </style> <style name="DeterminateLinearProgressDrawableStyle" parent="Material.Drawable.LinearProgress.Determinate"> <item name="lpd_strokeColor">#FF4389F3</item> <item name="lpd_strokeSecondaryColor">#FFB6CDF2</item> </style> <style name="QueryLinearProgressDrawableStyle" parent="Material.Drawable.LinearProgress.Query"> <item name="lpd_strokeColor">#FF4389F3</item> <item name="lpd_strokeSecondaryColor">#FFB6CDF2</item> </style> <style name="BufferLinearProgressDrawableStyle" parent="Material.Drawable.LinearProgress.Buffer"> <item name="lpd_strokeColor">#FF4389F3</item> <item name="lpd_strokeSecondaryColor">#FFB6CDF2</item> <item name="lpd_travelDuration">400</item> <item name="lpd_transformDuration">400</item> <item name="lpd_keepDuration">100</item> </style> <style name="Material"></style> <style name="Material.Drawable"></style> <style name="Material.Widget"></style> <style name="Material.App"></style> <style name="Material.TextAppearance"></style> <style name="Material.Drawable.CircularProgress"> <item name="cpd_padding">0dp</item> <item name="cpd_initialAngle">0</item> <item name="cpd_maxSweepAngle">270</item> <item name="cpd_minSweepAngle">1</item> <item name="cpd_strokeSize">4dp</item> <item name="cpd_strokeColor">?attr/colorPrimary</item> <item name="cpd_strokeSecondaryColor">@android:color/transparent</item> <item name="cpd_reverse">false</item> <item name="cpd_rotateDuration">1000</item> <item name="cpd_transformDuration">600</item> <item name="cpd_keepDuration">200</item> <item name="cpd_transformInterpolator">@android:anim/decelerate_interpolator</item> <item name="pv_progressMode">indeterminate</item> <item name="cpd_inAnimDuration">0</item> <item name="cpd_outAnimDuration">@android:integer/config_mediumAnimTime</item> </style> <style name="Material.Drawable.CircularProgress.Determinate" parent="Material.Drawable.CircularProgress"> <item name="pv_progressMode">determinate</item> <item name="cpd_inAnimDuration">@android:integer/config_mediumAnimTime</item> </style> <style name="Material.Drawable.LinearProgress"> <item name="lpd_maxLineWidth">75%</item> <item name="lpd_minLineWidth">10%</item> <item name="lpd_strokeSize">4dp</item> <item name="lpd_strokeColor">?attr/colorPrimary</item> <item name="lpd_strokeSecondaryColor">?attr/colorControlNormal</item> <item name="lpd_reverse">false</item> <item name="lpd_travelDuration">1000</item> <item name="lpd_transformDuration">600</item> <item name="lpd_keepDuration">200</item> <item name="lpd_transformInterpolator">@android:anim/decelerate_interpolator</item> <item name="pv_progressMode">indeterminate</item> <item name="lpd_inAnimDuration">@android:integer/config_mediumAnimTime</item> <item name="lpd_outAnimDuration">@android:integer/config_mediumAnimTime</item> <item name="lpd_verticalAlign">bottom</item> </style> <style name="Material.Drawable.LinearProgress.Determinate" parent="Material.Drawable.LinearProgress"> <item name="pv_progressMode">determinate</item> </style> <style name="Material.Drawable.LinearProgress.Query" parent="Material.Drawable.LinearProgress"> <item name="pv_progressMode">query</item> </style> <style name="Material.Drawable.LinearProgress.Buffer" parent="Material.Drawable.LinearProgress"> <item name="pv_progressMode">buffer</item> </style> <style name="Material.Widget.ProgressView"> <item name="pv_progress">0</item> </style> <style name="Material.Widget.ProgressView.Circular" parent="Material.Widget.ProgressView"> <item name="pv_autostart">true</item> <item name="pv_circular">true</item> <item name="pv_progressStyle">@style/Material.Drawable.CircularProgress</item> <item name="pv_progressMode">indeterminate</item> </style> <style name="Material.Widget.ProgressView.Circular.Determinate" parent="Material.Widget.ProgressView.Circular"> <item name="pv_progressStyle">@style/Material.Drawable.CircularProgress.Determinate</item> <item name="pv_progressMode">determinate</item> </style> <style name="Material.Widget.ProgressView.Linear" parent="Material.Widget.ProgressView"> <item name="pv_autostart">true</item> <item name="pv_circular">false</item> <item name="pv_progressStyle">@style/Material.Drawable.LinearProgress</item> <item name="pv_progressMode">indeterminate</item> </style> <style name="Material.Widget.ProgressView.Linear.Determinate" parent="Material.Widget.ProgressView.Linear"> <item name="pv_progressStyle">@style/Material.Drawable.LinearProgress.Determinate</item> <item name="pv_progressMode">determinate</item> </style> <style name="Material.Widget.ProgressView.Linear.Query" parent="Material.Widget.ProgressView.Linear"> <item name="pv_progressStyle">@style/Material.Drawable.LinearProgress.Query</item> <item name="pv_progressMode">query</item> </style> <style name="Material.Widget.ProgressView.Linear.Buffer" parent="Material.Widget.ProgressView.Linear"> <item name="pv_progressStyle">@style/Material.Drawable.LinearProgress.Buffer</item> <item name="pv_progressMode">buffer</item> </style> </resources>
open MyActivity.java file…
package com.example.materialprogressdailogdesign; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Handler.Callback; import android.os.Message; import android.view.View; import com.example.material.widget.ProgressView; public class MainActivity extends Activity implements Callback{ private ProgressView pv_circular; private ProgressView pv_circular_colors; private ProgressView pv_circular_inout; private ProgressView pv_circular_inout_colors; private ProgressView pv_circular_determinate_in_out; private ProgressView pv_circular_determinate; private ProgressView pv_linear; private ProgressView pv_linear_colors; private ProgressView pv_linear_determinate; private ProgressView pv_linear_query; private ProgressView pv_linear_buffer; private Handler mHandler; private static final int MSG_START_PROGRESS = 1000; private static final int MSG_STOP_PROGRESS = 1001; private static final int MSG_UPDATE_PROGRESS = 1002; private static final int MSG_UPDATE_QUERY_PROGRESS = 1003; private static final int MSG_UPDATE_BUFFER_PROGRESS = 1004; private static final long PROGRESS_INTERVAL = 7000; private static final long START_DELAY = 2000; private static final long PROGRESS_UPDATE_INTERVAL = PROGRESS_INTERVAL / 100; private static final long START_QUERY_DELAY = PROGRESS_INTERVAL / 2; private static final long QUERY_PROGRESS_UPDATE_INTERVAL = (PROGRESS_INTERVAL - START_QUERY_DELAY) / 100; private static final long BUFFER_PROGRESS_UPDATE_INTERVAL = (PROGRESS_INTERVAL - START_QUERY_DELAY) / 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pv_circular = (ProgressView)findViewById(R.id.progress_pv_circular); pv_circular_colors = (ProgressView)findViewById(R.id.progress_pv_circular_colors); pv_circular_inout = (ProgressView)findViewById(R.id.progress_pv_circular_inout); pv_circular_inout_colors = (ProgressView)findViewById(R.id.progress_pv_circular_inout_colors); pv_circular_determinate_in_out = (ProgressView)findViewById(R.id.progress_pv_circular_determinate_in_out); pv_circular_determinate = (ProgressView)findViewById(R.id.progress_pv_circular_determinate); pv_linear = (ProgressView)findViewById(R.id.progress_pv_linear); pv_linear_colors = (ProgressView)findViewById(R.id.progress_pv_linear_colors); pv_linear_determinate = (ProgressView)findViewById(R.id.progress_pv_linear_determinate); pv_linear_query = (ProgressView)findViewById(R.id.progress_pv_linear_query); pv_linear_buffer = (ProgressView)findViewById(R.id.progress_pv_linear_buffer); mHandler = new Handler(this); } @Override public void onPause() { super.onPause(); mHandler.removeCallbacksAndMessages(null); pv_circular_determinate_in_out.setVisibility(View.GONE); } @Override public void onResume() { super.onResume(); mHandler.sendEmptyMessageDelayed(MSG_START_PROGRESS, START_DELAY); } @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_START_PROGRESS: pv_circular.start(); pv_circular_colors.start(); pv_circular_inout.start(); pv_circular_inout_colors.start(); pv_circular_determinate_in_out.setProgress(0f); pv_circular_determinate_in_out.start(); pv_circular_determinate.setProgress(0f); pv_circular_determinate.start(); pv_linear.start(); pv_linear_colors.start(); pv_linear_determinate.setProgress(0f); pv_linear_determinate.start(); pv_linear_query.setProgress(0f); pv_linear_query.start(); pv_linear_buffer.setProgress(0f); pv_linear_buffer.setSecondaryProgress(0f); pv_linear_buffer.start(); mHandler.sendEmptyMessageDelayed(MSG_STOP_PROGRESS, PROGRESS_INTERVAL); mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PROGRESS, PROGRESS_UPDATE_INTERVAL); mHandler.sendEmptyMessageDelayed(MSG_UPDATE_QUERY_PROGRESS, START_QUERY_DELAY); mHandler.sendEmptyMessageDelayed(MSG_UPDATE_BUFFER_PROGRESS, BUFFER_PROGRESS_UPDATE_INTERVAL); break; case MSG_UPDATE_QUERY_PROGRESS: pv_linear_query.setProgress(pv_linear_query.getProgress() + 0.01f); if(pv_linear_query.getProgress() < 1f) mHandler.sendEmptyMessageDelayed(MSG_UPDATE_QUERY_PROGRESS, QUERY_PROGRESS_UPDATE_INTERVAL); else pv_linear_query.stop(); break; case MSG_UPDATE_BUFFER_PROGRESS: pv_linear_buffer.setSecondaryProgress(pv_linear_buffer.getSecondaryProgress() + 0.01f); if(pv_linear_buffer.getSecondaryProgress() < 1f) mHandler.sendEmptyMessageDelayed(MSG_UPDATE_BUFFER_PROGRESS, BUFFER_PROGRESS_UPDATE_INTERVAL); break; case MSG_UPDATE_PROGRESS: pv_circular_determinate_in_out.setProgress(pv_circular_determinate_in_out.getProgress() + 0.01f); pv_circular_determinate.setProgress(pv_circular_determinate.getProgress() + 0.01f); pv_linear_determinate.setProgress(pv_linear_determinate.getProgress() + 0.01f); pv_linear_buffer.setProgress(pv_linear_buffer.getProgress() + 0.01f); if(pv_circular_determinate_in_out.getProgress() < 1f) mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PROGRESS, PROGRESS_UPDATE_INTERVAL); else{ pv_circular_determinate_in_out.stop(); pv_circular_determinate.stop(); pv_linear_determinate.stop(); pv_linear_buffer.stop(); } break; case MSG_STOP_PROGRESS: pv_circular.stop(); pv_circular_colors.stop(); pv_circular_inout.stop(); pv_circular_inout_colors.stop(); pv_linear.stop(); pv_linear_colors.stop(); mHandler.sendEmptyMessageDelayed(MSG_START_PROGRESS, START_DELAY); break; } return false; } }
ProgressView.java
package com.example.material.widget; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.View; import com.example.material.drawable.CircularProgressDrawable; import com.example.material.drawable.LinearProgressDrawable; import com.example.materialprogressdailogdesign.R; public class ProgressView extends View { private boolean mAutostart; private boolean mCircular; private int mProgressId; public static final int MODE_DETERMINATE = 0; public static final int MODE_INDETERMINATE = 1; public static final int MODE_BUFFER = 2; public static final int MODE_QUERY = 3; private Drawable mProgressDrawable; public ProgressView(Context context) { this(context, null, 0, 0); } public ProgressView(Context context, AttributeSet attrs) { this(context, attrs, 0, 0); } public ProgressView(Context context, AttributeSet attrs, int defStyleAttr){ this(context, attrs, defStyleAttr, 0); } @SuppressWarnings("deprecation") @TargetApi(android.os.Build.VERSION_CODES.JELLY_BEAN) public ProgressView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr, defStyleRes); } private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){ applyStyle(context, attrs, defStyleAttr, defStyleRes); } public void applyStyle(int resId){ applyStyle(getContext(), null, 0, resId); } private void applyStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProgressView, defStyleAttr, defStyleRes); mAutostart = a.getBoolean(R.styleable.ProgressView_pv_autostart, true); mCircular = a.getBoolean(R.styleable.ProgressView_pv_circular, true); mProgressId = a.getResourceId(R.styleable.ProgressView_pv_progressStyle, 0); a.recycle(); if(mProgressId == 0) mProgressId = mCircular ? R.style.Material_Drawable_CircularProgress : R.style.Material_Drawable_LinearProgress; if(mCircular) mProgressDrawable = new CircularProgressDrawable.Builder(context, mProgressId).build(); else mProgressDrawable = new LinearProgressDrawable.Builder(context, mProgressId).build(); if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) setBackground(mProgressDrawable); else setBackgroundDrawable(mProgressDrawable); } @Override public void setVisibility(int v) { if(getVisibility() != v) { super.setVisibility(v); if (getProgressMode() == MODE_INDETERMINATE && mAutostart) { if (v == GONE || v == INVISIBLE) stop(); else start(); } } } @Override protected void onVisibilityChanged(@NonNull View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); if (getProgressMode() == MODE_INDETERMINATE && mAutostart) { if (visibility == GONE || visibility == INVISIBLE) stop(); else start(); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (getProgressMode() == MODE_INDETERMINATE && mAutostart) start(); } @Override protected void onDetachedFromWindow() { if (getProgressMode() == MODE_INDETERMINATE && mAutostart) stop(); super.onDetachedFromWindow(); } public int getProgressMode(){ if(mCircular) return ((CircularProgressDrawable)mProgressDrawable).getProgressMode(); else return ((LinearProgressDrawable)mProgressDrawable).getProgressMode(); } public float getProgress(){ if(mCircular) return ((CircularProgressDrawable)mProgressDrawable).getProgress(); else return ((LinearProgressDrawable)mProgressDrawable).getProgress(); } public float getSecondaryProgress(){ if(mCircular) return ((CircularProgressDrawable)mProgressDrawable).getSecondaryProgress(); else return ((LinearProgressDrawable)mProgressDrawable).getSecondaryProgress(); } public void setProgress(float percent){ if(mCircular) ((CircularProgressDrawable)mProgressDrawable).setProgress(percent); else ((LinearProgressDrawable)mProgressDrawable).setProgress(percent); } public void setSecondaryProgress(float percent){ if(mCircular) ((CircularProgressDrawable)mProgressDrawable).setSecondaryProgress(percent); else ((LinearProgressDrawable)mProgressDrawable).setSecondaryProgress(percent); } public void start(){ if(mProgressDrawable != null) ((Animatable)mProgressDrawable).start(); } public void stop(){ if(mProgressDrawable != null) ((Animatable)mProgressDrawable).stop(); } }
ViewUtil.java
package com.example.material.util; import java.util.concurrent.atomic.AtomicInteger; import android.annotation.SuppressLint; public class ViewUtil { public static final long FRAME_DURATION = 1000 / 60; private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); @SuppressLint("NewApi") public static int generateViewId() { if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { for (;;) { final int result = sNextGeneratedId.get(); // aapt-generated IDs have the high byte nonzero; clamp to the range under that. int newValue = result + 1; if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. if (sNextGeneratedId.compareAndSet(result, newValue)) return result; } } else return android.view.View.generateViewId(); } public static boolean hasState(int[] states, int state){ if(states == null) return false; for (int state1 : states) if (state1 == state) return true; return false; } }
TypefaceUtil.java
package com.example.material.util; import android.content.Context; import android.graphics.Typeface; import java.util.HashMap; /** * Created by Rey on 12/23/2014. */ public class TypefaceUtil { private static final HashMap<String, Typeface> sCachedFonts = new HashMap<String, Typeface>(); private static final String PREFIX_ASSET = "asset:"; private TypefaceUtil() { } /** * @param familyName if start with 'asset:' prefix, then load font from asset folder. * @return */ public static Typeface load(Context context, String familyName, int style) { if(familyName != null && familyName.startsWith(PREFIX_ASSET)) synchronized (sCachedFonts) { try { if (!sCachedFonts.containsKey(familyName)) { final Typeface typeface = Typeface.createFromAsset(context.getAssets(), familyName); sCachedFonts.put(familyName, typeface); return typeface; } } catch (Exception e) { return Typeface.DEFAULT; } return sCachedFonts.get(familyName); } return Typeface.create(familyName, style); } }
ThemeUtil.java
package com.example.material.util; import com.example.materialprogressdailogdesign.R; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.os.Build; import android.support.v7.internal.widget.TintTypedArray; import android.util.TypedValue; public class ThemeUtil { private static TypedValue value; public static int dpToPx(Context context, int dp){ return (int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()) + 0.5f); } public static int spToPx(Context context, int sp){ return (int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()) + 0.5f); } private static int getColor(Context context, int id, int defaultValue){ if(value == null) value = new TypedValue(); try{ Theme theme = context.getTheme(); if(theme != null && theme.resolveAttribute(id, value, true)){ if (value.type >= TypedValue.TYPE_FIRST_INT && value.type <= TypedValue.TYPE_LAST_INT) return value.data; else if (value.type == TypedValue.TYPE_STRING) return context.getResources().getColor(value.resourceId); } } catch(Exception ex){} return defaultValue; } public static int windowBackground(Context context, int defaultValue){ return getColor(context, android.R.attr.windowBackground, defaultValue); } public static int textColorPrimary(Context context, int defaultValue){ return getColor(context, android.R.attr.textColorPrimary, defaultValue); } public static int textColorSecondary(Context context, int defaultValue){ return getColor(context, android.R.attr.textColorSecondary, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorPrimary(Context context, int defaultValue){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return getColor(context, android.R.attr.colorPrimary, defaultValue); return getColor(context, R.attr.colorPrimary, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorPrimaryDark(Context context, int defaultValue){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return getColor(context, android.R.attr.colorPrimaryDark, defaultValue); return getColor(context, R.attr.colorPrimaryDark, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorAccent(Context context, int defaultValue){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return getColor(context, android.R.attr.colorAccent, defaultValue); return getColor(context, R.attr.colorAccent, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorControlNormal(Context context, int defaultValue){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return getColor(context, android.R.attr.colorControlNormal, defaultValue); return getColor(context, R.attr.colorControlNormal, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorControlActivated(Context context, int defaultValue){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return getColor(context, android.R.attr.colorControlActivated, defaultValue); return getColor(context, R.attr.colorControlActivated, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorControlHighlight(Context context, int defaultValue){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return getColor(context, android.R.attr.colorControlHighlight, defaultValue); return getColor(context, R.attr.colorControlHighlight, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorButtonNormal(Context context, int defaultValue){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return getColor(context, android.R.attr.colorButtonNormal, defaultValue); return getColor(context, R.attr.colorButtonNormal, defaultValue); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static int colorSwitchThumbNormal(Context context, int defaultValue){ return getColor(context, R.attr.colorSwitchThumbNormal, defaultValue); } public static int getType(TypedArray array, int index){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return array.getType(index); else{ TypedValue value = array.peekValue(index); return value == null ? TypedValue.TYPE_NULL : value.type; } } public static CharSequence getString(TypedArray array, int index, CharSequence defaultValue){ String result = array.getString(index); return result == null ? defaultValue : result; } public static CharSequence getString(TintTypedArray array, int index, CharSequence defaultValue){ String result = array.getString(index); return result == null ? defaultValue : result; } }
ColorUtil.java
package com.example.material.util; import android.graphics.Color; public class ColorUtil { private static int getMiddleValue(int prev, int next, float factor){ return Math.round(prev + (next - prev) * factor); } public static int getMiddleColor(int prevColor, int curColor, float factor){ if(prevColor == curColor) return curColor; if(factor == 0f) return prevColor; else if(factor == 1f) return curColor; int a = getMiddleValue(Color.alpha(prevColor), Color.alpha(curColor), factor); int r = getMiddleValue(Color.red(prevColor), Color.red(curColor), factor); int g = getMiddleValue(Color.green(prevColor), Color.green(curColor), factor); int b = getMiddleValue(Color.blue(prevColor), Color.blue(curColor), factor); return Color.argb(a, r, g, b); } public static int getColor(int baseColor, float alphaPercent){ int alpha = Math.round(Color.alpha(baseColor) * alphaPercent); return (baseColor & 0x00FFFFFF) | (alpha << 24); } }
LinearProgressDrawable.java
package com.example.material.drawable; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathEffect; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.util.AttributeSet; import android.util.TypedValue; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import com.example.material.util.ColorUtil; import com.example.material.util.ThemeUtil; import com.example.material.util.ViewUtil; import com.example.material.widget.ProgressView; import com.example.materialprogressdailogdesign.R; public class LinearProgressDrawable extends Drawable implements Animatable { private long mLastUpdateTime; private long mLastProgressStateTime; private long mLastRunStateTime; private int mProgressState; private static final int PROGRESS_STATE_STRETCH = 0; private static final int PROGRESS_STATE_KEEP_STRETCH = 1; private static final int PROGRESS_STATE_SHRINK = 2; private static final int PROGRESS_STATE_KEEP_SHRINK = 3; private int mRunState = RUN_STATE_STOPPED; private static final int RUN_STATE_STOPPED = 0; private static final int RUN_STATE_STARTING = 1; private static final int RUN_STATE_STARTED = 2; private static final int RUN_STATE_RUNNING = 3; private static final int RUN_STATE_STOPPING = 4; public static final int ALIGN_TOP = 0; public static final int ALIGN_CENTER = 1; public static final int ALIGN_BOTTOM = 2; private Paint mPaint; private float mStartLine; private float mLineWidth; private int mStrokeColorIndex; private float mAnimTime; private Path mPath; private DashPathEffect mPathEffect; private float mProgressPercent; private float mSecondaryProgressPercent; private int mMaxLineWidth; private float mMaxLineWidthPercent; private int mMinLineWidth; private float mMinLineWidthPercent; private int mStrokeSize; private int mVerticalAlign; private int[] mStrokeColors; private int mStrokeSecondaryColor; private boolean mReverse; private int mTravelDuration; private int mTransformDuration; private int mKeepDuration; private int mInAnimationDuration; private int mOutAnimationDuration; private int mProgressMode; private Interpolator mTransformInterpolator; private LinearProgressDrawable(float progressPercent, float secondaryProgressPercent, int maxLineWidth, float maxLineWidthPercent, int minLineWidth, float minLineWidthPercent, int strokeSize, int verticalAlign, int[] strokeColors, int strokeSecondaryColor, boolean reverse, int travelDuration, int transformDuration, int keepDuration, Interpolator transformInterpolator, int progressMode, int inAnimDuration, int outAnimDuration){ setProgress(progressPercent); setSecondaryProgress(secondaryProgressPercent); mMaxLineWidth = maxLineWidth; mMaxLineWidthPercent = maxLineWidthPercent; mMinLineWidth = minLineWidth; mMinLineWidthPercent = minLineWidthPercent; mStrokeSize = strokeSize; mVerticalAlign = verticalAlign; mStrokeColors = strokeColors; mStrokeSecondaryColor = strokeSecondaryColor; mReverse = reverse; mTravelDuration = travelDuration; mTransformDuration = transformDuration; mKeepDuration = keepDuration; mTransformInterpolator = transformInterpolator; mProgressMode = progressMode; mInAnimationDuration = inAnimDuration; mOutAnimationDuration = outAnimDuration; mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeJoin(Paint.Join.ROUND); mPath = new Path(); } @Override public void draw(Canvas canvas) { switch (mProgressMode) { case ProgressView.MODE_DETERMINATE: drawDeterminate(canvas); break; case ProgressView.MODE_INDETERMINATE: drawIndeterminate(canvas); break; case ProgressView.MODE_BUFFER: drawBuffer(canvas); break; case ProgressView.MODE_QUERY: drawQuery(canvas); break; } } private void drawLinePath(Canvas canvas, float x1, float y1, float x2, float y2, Paint paint){ mPath.reset(); mPath.moveTo(x1, y1); mPath.lineTo(x2, y2); canvas.drawPath(mPath, paint); } private void drawDeterminate(Canvas canvas){ Rect bounds = getBounds(); int width = bounds.width(); float size = 0f; if(mRunState == RUN_STATE_STARTING) size = (float)mStrokeSize * Math.min(mInAnimationDuration, (SystemClock.uptimeMillis() - mLastRunStateTime)) / mInAnimationDuration; else if(mRunState == RUN_STATE_STOPPING) size = (float)mStrokeSize * Math.max(0, (mOutAnimationDuration - SystemClock.uptimeMillis() + mLastRunStateTime)) / mOutAnimationDuration; else if(mRunState != RUN_STATE_STOPPED) size = mStrokeSize; if(size > 0){ float y = 0; float lineWidth = width * mProgressPercent; switch (mVerticalAlign) { case ALIGN_TOP: y = size / 2; break; case ALIGN_CENTER: y = bounds.height() / 2f; break; case ALIGN_BOTTOM: y = bounds.height() - size / 2; break; } mPaint.setStrokeWidth(size); mPaint.setStyle(Paint.Style.STROKE); if(mProgressPercent != 1f){ mPaint.setColor(mStrokeSecondaryColor); if(mReverse) canvas.drawLine(0, y, width - lineWidth, y, mPaint); else canvas.drawLine(lineWidth, y, width, y, mPaint); } if(mProgressPercent != 0f){ mPaint.setColor(mStrokeColors[0]); if(mReverse) drawLinePath(canvas, width - lineWidth, y, width, y, mPaint); else drawLinePath(canvas, 0, y, lineWidth, y, mPaint); } } } private int getIndeterminateStrokeColor(){ if(mProgressState != PROGRESS_STATE_KEEP_SHRINK || mStrokeColors.length == 1) return mStrokeColors[mStrokeColorIndex]; float value = Math.max(0f, Math.min(1f, (float)(SystemClock.uptimeMillis() - mLastProgressStateTime) / mKeepDuration)); int prev_index = mStrokeColorIndex == 0 ? mStrokeColors.length - 1 : mStrokeColorIndex - 1; return ColorUtil.getMiddleColor(mStrokeColors[prev_index], mStrokeColors[mStrokeColorIndex], value); } private void drawIndeterminate(Canvas canvas){ Rect bounds = getBounds(); int width = bounds.width(); float size = 0f; if(mRunState == RUN_STATE_STARTING) size = (float)mStrokeSize * Math.min(mInAnimationDuration, (SystemClock.uptimeMillis() - mLastRunStateTime)) / mInAnimationDuration; else if(mRunState == RUN_STATE_STOPPING) size = (float)mStrokeSize * Math.max(0, (mOutAnimationDuration - SystemClock.uptimeMillis() + mLastRunStateTime)) / mOutAnimationDuration; else if(mRunState != RUN_STATE_STOPPED) size = mStrokeSize; if(size > 0){ float y = 0; switch (mVerticalAlign) { case ALIGN_TOP: y = size / 2; break; case ALIGN_CENTER: y = bounds.height() / 2f; break; case ALIGN_BOTTOM: y = bounds.height() - size / 2; break; } mPaint.setStrokeWidth(size); mPaint.setStyle(Paint.Style.STROKE); float endLine = offset(mStartLine, mLineWidth, width); if(mReverse){ if(endLine <= mStartLine){ mPaint.setColor(mStrokeSecondaryColor); if(endLine > 0) canvas.drawLine(0, y, endLine, y, mPaint); if(mStartLine < width) canvas.drawLine(mStartLine, y, width, y, mPaint); mPaint.setColor(getIndeterminateStrokeColor()); drawLinePath(canvas, endLine, y, mStartLine, y, mPaint); } else{ mPaint.setColor(mStrokeSecondaryColor); canvas.drawLine(mStartLine, y, endLine, y, mPaint); mPaint.setColor(getIndeterminateStrokeColor()); mPath.reset(); if(mStartLine > 0){ mPath.moveTo(0, y); mPath.lineTo(mStartLine, y); } if(endLine < width){ mPath.moveTo(endLine, y); mPath.lineTo(width, y); } canvas.drawPath(mPath, mPaint); } } else{ if(endLine >= mStartLine){ mPaint.setColor(mStrokeSecondaryColor); if(mStartLine > 0) canvas.drawLine(0, y, mStartLine, y, mPaint); if(endLine < width) canvas.drawLine(endLine, y, width, y, mPaint); mPaint.setColor(getIndeterminateStrokeColor()); drawLinePath(canvas, mStartLine, y, endLine, y, mPaint); } else{ mPaint.setColor(mStrokeSecondaryColor); canvas.drawLine(endLine, y, mStartLine, y, mPaint); mPaint.setColor(getIndeterminateStrokeColor()); mPath.reset(); if(endLine > 0){ mPath.moveTo(0, y); mPath.lineTo(endLine, y); } if(mStartLine < width){ mPath.moveTo(mStartLine, y); mPath.lineTo(width, y); } canvas.drawPath(mPath, mPaint); } } } } private PathEffect getPathEffect(){ if(mPathEffect == null) mPathEffect = new DashPathEffect(new float[]{0.1f, mStrokeSize * 2}, 0f); return mPathEffect; } private void drawBuffer(Canvas canvas){ Rect bounds = getBounds(); int width = bounds.width(); float size = 0f; if(mRunState == RUN_STATE_STARTING) size = (float)mStrokeSize * Math.min(mInAnimationDuration, (SystemClock.uptimeMillis() - mLastRunStateTime)) / mInAnimationDuration; else if(mRunState == RUN_STATE_STOPPING) size = (float)mStrokeSize * Math.max(0, (mOutAnimationDuration - SystemClock.uptimeMillis() + mLastRunStateTime)) / mOutAnimationDuration; else if(mRunState != RUN_STATE_STOPPED) size = mStrokeSize; if(size > 0){ float y = 0; float lineWidth = width * mProgressPercent; float secondaryLineWidth = width * mSecondaryProgressPercent; switch (mVerticalAlign) { case ALIGN_TOP: y = size / 2; break; case ALIGN_CENTER: y = bounds.height() / 2f; break; case ALIGN_BOTTOM: y = bounds.height() - size / 2; break; } mPaint.setStyle(Paint.Style.STROKE); if(mProgressPercent != 1f){ mPaint.setStrokeWidth(size); mPaint.setColor(mStrokeSecondaryColor); mPaint.setPathEffect(null); if(mReverse) drawLinePath(canvas, width - secondaryLineWidth, y, width - lineWidth, y, mPaint); else drawLinePath(canvas, secondaryLineWidth, y, lineWidth, y, mPaint); mPaint.setStrokeWidth(mLineWidth); mPaint.setPathEffect(getPathEffect()); float offset = mStrokeSize * 2 - mStartLine; if(mReverse) drawLinePath(canvas, -offset, y, width - secondaryLineWidth, y, mPaint); else drawLinePath(canvas, width + offset, y, secondaryLineWidth, y, mPaint); } if(mProgressPercent != 0f){ mPaint.setStrokeWidth(size); mPaint.setColor(mStrokeColors[0]); mPaint.setPathEffect(null); if(mReverse) drawLinePath(canvas, width - lineWidth, y, width, y, mPaint); else drawLinePath(canvas, 0, y, lineWidth, y, mPaint); } } } private int getQueryStrokeColor(){ return ColorUtil.getColor(mStrokeColors[0], mAnimTime); } private void drawQuery(Canvas canvas){ Rect bounds = getBounds(); int width = bounds.width(); float size = 0f; if(mRunState == RUN_STATE_STARTING) size = (float)mStrokeSize * Math.min(mInAnimationDuration, (SystemClock.uptimeMillis() - mLastRunStateTime)) / mInAnimationDuration; else if(mRunState == RUN_STATE_STOPPING) size = (float)mStrokeSize * Math.max(0, (mOutAnimationDuration - SystemClock.uptimeMillis() + mLastRunStateTime)) / mOutAnimationDuration; else if(mRunState != RUN_STATE_STOPPED) size = mStrokeSize; if(size > 0){ float y = 0; switch (mVerticalAlign) { case ALIGN_TOP: y = size / 2; break; case ALIGN_CENTER: y = bounds.height() / 2f; break; case ALIGN_BOTTOM: y = bounds.height() - size / 2; break; } mPaint.setStrokeWidth(size); mPaint.setStyle(Paint.Style.STROKE); if(mProgressPercent != 1f){ mPaint.setColor(mStrokeSecondaryColor); canvas.drawLine(0, y, width, y, mPaint); if(mAnimTime < 1f){ float endLine = Math.max(0, Math.min(width, mStartLine + mLineWidth)); mPaint.setColor(getQueryStrokeColor()); drawLinePath(canvas, mStartLine, y, endLine, y, mPaint); } } if(mProgressPercent != 0f){ float lineWidth = width * mProgressPercent; mPaint.setColor(mStrokeColors[0]); if(mReverse) drawLinePath(canvas, width - lineWidth, y, width, y, mPaint); else drawLinePath(canvas, 0, y, lineWidth, y, mPaint); } } } @Override public void setAlpha(int alpha) { mPaint.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } public int getProgressMode(){ return mProgressMode; } public float getProgress(){ return mProgressPercent; } public float getSecondaryProgress(){ return mSecondaryProgressPercent; } public void setProgress(float percent){ percent = Math.min(1f, Math.max(0f, percent)); if(mProgressPercent != percent){ mProgressPercent = percent; if(isRunning()) invalidateSelf(); else if(mProgressPercent != 0f) start(); } } public void setSecondaryProgress(float percent){ percent = Math.min(1f, Math.max(0f, percent)); if(mSecondaryProgressPercent != percent){ mSecondaryProgressPercent = percent; if(isRunning()) invalidateSelf(); else if(mSecondaryProgressPercent != 0f) start(); } } //Animation: based on http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/ private void resetAnimation(){ mLastUpdateTime = SystemClock.uptimeMillis(); mLastProgressStateTime = mLastUpdateTime; if(mProgressMode == ProgressView.MODE_INDETERMINATE){ mStartLine = mReverse ? getBounds().width() : 0; mStrokeColorIndex = 0; mLineWidth = mReverse ? -mMinLineWidth : mMinLineWidth; mProgressState = PROGRESS_STATE_STRETCH; } else if(mProgressMode == ProgressView.MODE_BUFFER){ mStartLine = 0; } else if(mProgressMode == ProgressView.MODE_QUERY){ mStartLine = !mReverse ? getBounds().width() : 0; mStrokeColorIndex = 0; mLineWidth = !mReverse ? -mMaxLineWidth : mMaxLineWidth; } } @Override public void start() { start(mInAnimationDuration > 0); } @Override public void stop() { stop(mOutAnimationDuration > 0); } private void start(boolean withAnimation){ if(isRunning()) return; if(withAnimation){ mRunState = RUN_STATE_STARTING; mLastRunStateTime = SystemClock.uptimeMillis(); } resetAnimation(); scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } private void stop(boolean withAnimation){ if(!isRunning()) return; if(withAnimation){ mLastRunStateTime = SystemClock.uptimeMillis(); if(mRunState == RUN_STATE_STARTED){ scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } mRunState = RUN_STATE_STOPPING; } else{ mRunState = RUN_STATE_STOPPED; unscheduleSelf(mUpdater); invalidateSelf(); } } @Override public boolean isRunning() { return mRunState != RUN_STATE_STOPPED; } @Override public void scheduleSelf(Runnable what, long when) { if(mRunState == RUN_STATE_STOPPED) mRunState = mInAnimationDuration > 0 ? RUN_STATE_STARTING : RUN_STATE_RUNNING; super.scheduleSelf(what, when); } private final Runnable mUpdater = new Runnable() { @Override public void run() { update(); } }; private void update(){ switch (mProgressMode) { case ProgressView.MODE_DETERMINATE: updateDeterminate(); break; case ProgressView.MODE_INDETERMINATE: updateIndeterminate(); break; case ProgressView.MODE_BUFFER: updateBuffer(); break; case ProgressView.MODE_QUERY: updateQuery(); break; } } private void updateDeterminate(){ long curTime = SystemClock.uptimeMillis(); if(mRunState == RUN_STATE_STARTING){ if(curTime - mLastRunStateTime > mInAnimationDuration){ mRunState = RUN_STATE_STARTED; return; } } else if(mRunState == RUN_STATE_STOPPING){ if(curTime - mLastRunStateTime > mOutAnimationDuration){ stop(false); return; } } if(isRunning()) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } private float offset(float pos, float offset, float max){ pos += offset; if(pos > max) return pos - max; if(pos < 0) return max + pos; return pos; } private void updateIndeterminate(){ Rect bounds = getBounds(); int width = bounds.width(); long curTime = SystemClock.uptimeMillis(); float travelOffset = (float)(curTime - mLastUpdateTime) * width / mTravelDuration; if(mReverse) travelOffset = -travelOffset; mLastUpdateTime = curTime; switch (mProgressState) { case PROGRESS_STATE_STRETCH: if(mTransformDuration <= 0){ mLineWidth = mMinLineWidth == 0 ? width * mMinLineWidthPercent : mMinLineWidth; if(mReverse) mLineWidth = -mLineWidth; mStartLine = offset(mStartLine, travelOffset, width); mProgressState = PROGRESS_STATE_KEEP_STRETCH; mLastProgressStateTime = curTime; } else{ float value = (curTime - mLastProgressStateTime) / (float)mTransformDuration; float maxWidth = mMaxLineWidth == 0 ? width * mMaxLineWidthPercent : mMaxLineWidth; float minWidth = mMinLineWidth == 0 ? width * mMinLineWidthPercent : mMinLineWidth; mStartLine = offset(mStartLine, travelOffset, width); mLineWidth = mTransformInterpolator.getInterpolation(value) * (maxWidth - minWidth) + minWidth; if(mReverse) mLineWidth = -mLineWidth; if(value > 1f){ mLineWidth = mReverse ? -maxWidth : maxWidth; mProgressState = PROGRESS_STATE_KEEP_STRETCH; mLastProgressStateTime = curTime; } } break; case PROGRESS_STATE_KEEP_STRETCH: mStartLine = offset(mStartLine, travelOffset, width); if(curTime - mLastProgressStateTime > mKeepDuration){ mProgressState = PROGRESS_STATE_SHRINK; mLastProgressStateTime = curTime; } break; case PROGRESS_STATE_SHRINK: if(mTransformDuration <= 0){ mLineWidth = mMinLineWidth == 0 ? width * mMinLineWidthPercent : mMinLineWidth; if(mReverse) mLineWidth = -mLineWidth; mStartLine = offset(mStartLine, travelOffset, width); mProgressState = PROGRESS_STATE_KEEP_SHRINK; mLastProgressStateTime = curTime; mStrokeColorIndex = (mStrokeColorIndex + 1) % mStrokeColors.length; } else{ float value = (curTime - mLastProgressStateTime) / (float)mTransformDuration; float maxWidth = mMaxLineWidth == 0 ? width * mMaxLineWidthPercent : mMaxLineWidth; float minWidth = mMinLineWidth == 0 ? width * mMinLineWidthPercent : mMinLineWidth; float newLineWidth = (1f - mTransformInterpolator.getInterpolation(value)) * (maxWidth - minWidth) + minWidth; if(mReverse) newLineWidth = -newLineWidth; mStartLine = offset(mStartLine, travelOffset + mLineWidth - newLineWidth, width); mLineWidth = newLineWidth; if(value > 1f){ mLineWidth = mReverse ? -minWidth : minWidth; mProgressState = PROGRESS_STATE_KEEP_SHRINK; mLastProgressStateTime = curTime; mStrokeColorIndex = (mStrokeColorIndex + 1) % mStrokeColors.length; } } break; case PROGRESS_STATE_KEEP_SHRINK: mStartLine = offset(mStartLine, travelOffset, width); if(curTime - mLastProgressStateTime > mKeepDuration){ mProgressState = PROGRESS_STATE_STRETCH; mLastProgressStateTime = curTime; } break; } if(mRunState == RUN_STATE_STARTING){ if(curTime - mLastRunStateTime > mInAnimationDuration) mRunState = RUN_STATE_RUNNING; } else if(mRunState == RUN_STATE_STOPPING){ if(curTime - mLastRunStateTime > mOutAnimationDuration){ stop(false); return; } } if (isRunning()) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } private void updateBuffer(){ long curTime = SystemClock.uptimeMillis(); float maxDistance = mStrokeSize * 2; mStartLine += maxDistance * (float)(curTime - mLastUpdateTime) / mTravelDuration; while(mStartLine > maxDistance) mStartLine -= maxDistance; mLastUpdateTime = curTime; switch (mProgressState) { case PROGRESS_STATE_STRETCH: if(mTransformDuration <= 0){ mProgressState = PROGRESS_STATE_KEEP_STRETCH; mLastProgressStateTime = curTime; } else{ float value = (curTime - mLastProgressStateTime) / (float)mTransformDuration; mLineWidth = mTransformInterpolator.getInterpolation(value) * mStrokeSize; if(value > 1f){ mLineWidth = mStrokeSize; mProgressState = PROGRESS_STATE_KEEP_STRETCH; mLastProgressStateTime = curTime; } } break; case PROGRESS_STATE_KEEP_STRETCH: if(curTime - mLastProgressStateTime > mKeepDuration){ mProgressState = PROGRESS_STATE_SHRINK; mLastProgressStateTime = curTime; } break; case PROGRESS_STATE_SHRINK: if(mTransformDuration <= 0){ mProgressState = PROGRESS_STATE_KEEP_SHRINK; mLastProgressStateTime = curTime; } else{ float value = (curTime - mLastProgressStateTime) / (float)mTransformDuration; mLineWidth = (1f - mTransformInterpolator.getInterpolation(value)) * mStrokeSize; if(value > 1f){ mLineWidth = 0; mProgressState = PROGRESS_STATE_KEEP_SHRINK; mLastProgressStateTime = curTime; } } break; case PROGRESS_STATE_KEEP_SHRINK: if(curTime - mLastProgressStateTime > mKeepDuration){ mProgressState = PROGRESS_STATE_STRETCH; mLastProgressStateTime = curTime; } break; } if(mRunState == RUN_STATE_STARTING){ if(curTime - mLastRunStateTime > mInAnimationDuration) mRunState = RUN_STATE_RUNNING; } else if(mRunState == RUN_STATE_STOPPING){ if(curTime - mLastRunStateTime > mOutAnimationDuration){ stop(false); return; } } if(isRunning()) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } private void updateQuery(){ long curTime = SystemClock.uptimeMillis(); mAnimTime = (float)(curTime - mLastProgressStateTime) / mTravelDuration; boolean requestUpdate = mRunState == RUN_STATE_STOPPING || mProgressPercent == 0 || mAnimTime < 1f; if(mAnimTime > 1f){ mLastProgressStateTime = Math.round(curTime - (mAnimTime - 1f) * mTravelDuration); mAnimTime -= 1f; } if(requestUpdate && mRunState != RUN_STATE_STOPPING){ Rect bounds = getBounds(); int width = bounds.width(); float maxWidth = mMaxLineWidth == 0 ? width * mMaxLineWidthPercent : mMaxLineWidth; float minWidth = mMinLineWidth == 0 ? width * mMinLineWidthPercent : mMinLineWidth; mLineWidth = mTransformInterpolator.getInterpolation(mAnimTime) * (minWidth - maxWidth) + maxWidth; if(mReverse) mLineWidth = -mLineWidth; mStartLine = mReverse ? mTransformInterpolator.getInterpolation(mAnimTime) * (width + minWidth) : ((1f - mTransformInterpolator.getInterpolation(mAnimTime)) * (width + minWidth) - minWidth); } if(mRunState == RUN_STATE_STARTING){ if(curTime - mLastRunStateTime > mInAnimationDuration) mRunState = RUN_STATE_RUNNING; } else if(mRunState == RUN_STATE_STOPPING){ if(curTime - mLastRunStateTime > mOutAnimationDuration){ stop(false); return; } } if (isRunning()){ if(requestUpdate) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); else if(mRunState == RUN_STATE_RUNNING) mRunState = RUN_STATE_STARTED; } invalidateSelf(); } public static class Builder{ private float mProgressPercent = 0; private float mSecondaryProgressPercent = 0; private int mMaxLineWidth; private float mMaxLineWidthPercent; private int mMinLineWidth; private float mMinLineWidthPercent; private int mStrokeSize = 8; private int mVerticalAlign = LinearProgressDrawable.ALIGN_BOTTOM; private int[] mStrokeColors; private int mStrokeSecondaryColor; private boolean mReverse = false; private int mTravelDuration = 1000; private int mTransformDuration = 800; private int mKeepDuration = 200; private Interpolator mTransformInterpolator; private int mProgressMode = ProgressView.MODE_INDETERMINATE; private int mInAnimationDuration = 400; private int mOutAnimationDuration = 400; public Builder(){} public Builder(Context context, int defStyleRes){ this(context, null, 0, defStyleRes); } public Builder(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LinearProgressDrawable, defStyleAttr, defStyleRes); int resId; progressPercent(a.getFloat(R.styleable.LinearProgressDrawable_pv_progress, 0)); secondaryProgressPercent(a.getFloat(R.styleable.LinearProgressDrawable_pv_secondaryProgress, 0)); TypedValue value = a.peekValue(R.styleable.LinearProgressDrawable_lpd_maxLineWidth); if(value == null) maxLineWidth(0.75f); else if(value.type == TypedValue.TYPE_FRACTION) maxLineWidth(a.getFraction(R.styleable.LinearProgressDrawable_lpd_maxLineWidth, 1, 1, 0.75f)); else maxLineWidth(a.getDimensionPixelSize(R.styleable.LinearProgressDrawable_lpd_maxLineWidth, 0)); value = a.peekValue(R.styleable.LinearProgressDrawable_lpd_minLineWidth); if(value == null) minLineWidth(0.25f); else if(value.type == TypedValue.TYPE_FRACTION) minLineWidth(a.getFraction(R.styleable.LinearProgressDrawable_lpd_minLineWidth, 1, 1, 0.25f)); else minLineWidth(a.getDimensionPixelSize(R.styleable.LinearProgressDrawable_lpd_minLineWidth, 0)); strokeSize(a.getDimensionPixelSize(R.styleable.LinearProgressDrawable_lpd_strokeSize, ThemeUtil.dpToPx(context, 4))); verticalAlign(a.getInteger(R.styleable.LinearProgressDrawable_lpd_verticalAlign, LinearProgressDrawable.ALIGN_BOTTOM)); strokeColors(a.getColor(R.styleable.LinearProgressDrawable_lpd_strokeColor, ThemeUtil.colorPrimary(context, 0xFF000000))); if((resId = a.getResourceId(R.styleable.LinearProgressDrawable_lpd_strokeColors, 0)) != 0){ TypedArray ta = context.getResources().obtainTypedArray(resId); int[] colors = new int[ta.length()]; for(int j = 0; j < ta.length(); j++) colors[j] = ta.getColor(j, 0); ta.recycle(); strokeColors(colors); } strokeSecondaryColor(a.getColor(R.styleable.LinearProgressDrawable_lpd_strokeSecondaryColor, 0)); reverse(a.getBoolean(R.styleable.LinearProgressDrawable_lpd_reverse, false)); travelDuration(a.getInteger(R.styleable.LinearProgressDrawable_lpd_travelDuration, context.getResources().getInteger(android.R.integer.config_longAnimTime))); transformDuration(a.getInteger(R.styleable.LinearProgressDrawable_lpd_transformDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime))); keepDuration(a.getInteger(R.styleable.LinearProgressDrawable_lpd_keepDuration, context.getResources().getInteger(android.R.integer.config_shortAnimTime))); if((resId = a.getResourceId(R.styleable.LinearProgressDrawable_lpd_transformInterpolator, 0)) != 0) transformInterpolator(AnimationUtils.loadInterpolator(context, resId)); progressMode(a.getInteger(R.styleable.LinearProgressDrawable_pv_progressMode, ProgressView.MODE_INDETERMINATE)); inAnimDuration(a.getInteger(R.styleable.LinearProgressDrawable_lpd_inAnimDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime))); outAnimDuration(a.getInteger(R.styleable.LinearProgressDrawable_lpd_outAnimDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime))); a.recycle(); } public LinearProgressDrawable build(){ if(mStrokeColors == null) mStrokeColors = new int[]{0xFF0099FF}; if(mTransformInterpolator == null) mTransformInterpolator = new DecelerateInterpolator(); return new LinearProgressDrawable(mProgressPercent, mSecondaryProgressPercent, mMaxLineWidth, mMaxLineWidthPercent, mMinLineWidth, mMinLineWidthPercent, mStrokeSize, mVerticalAlign, mStrokeColors, mStrokeSecondaryColor, mReverse, mTravelDuration, mTransformDuration, mKeepDuration, mTransformInterpolator, mProgressMode, mInAnimationDuration, mOutAnimationDuration); } public Builder secondaryProgressPercent(float percent){ mSecondaryProgressPercent = percent; return this; } public Builder progressPercent(float percent){ mProgressPercent = percent; return this; } public Builder maxLineWidth(int width){ mMaxLineWidth = width; return this; } public Builder maxLineWidth(float percent){ mMaxLineWidthPercent = Math.max(0f, Math.min(1f, percent)); mMaxLineWidth = 0; return this; } public Builder minLineWidth(int width){ mMinLineWidth = width; return this; } public Builder minLineWidth(float percent){ mMinLineWidthPercent = Math.max(0f, Math.min(1f, percent)); mMinLineWidth = 0; return this; } public Builder strokeSize(int strokeSize){ mStrokeSize = strokeSize; return this; } public Builder verticalAlign(int align){ mVerticalAlign = align; return this; } public Builder strokeColors(int... strokeColors){ mStrokeColors = strokeColors; return this; } public Builder strokeSecondaryColor(int color){ mStrokeSecondaryColor = color; return this; } public Builder reverse(boolean reverse){ mReverse = reverse; return this; } public Builder reverse(){ return reverse(true); } public Builder travelDuration(int duration){ mTravelDuration = duration; return this; } public Builder transformDuration(int duration){ mTransformDuration = duration; return this; } public Builder keepDuration(int duration){ mKeepDuration = duration; return this; } public Builder transformInterpolator(Interpolator interpolator){ mTransformInterpolator = interpolator; return this; } public Builder progressMode(int mode){ mProgressMode = mode; return this; } public Builder inAnimDuration(int duration){ mInAnimationDuration = duration; return this; } public Builder outAnimDuration(int duration){ mOutAnimationDuration = duration; return this; } } }
CircularProgressDrawable.java
package com.example.material.drawable; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.util.AttributeSet; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import com.example.material.util.ColorUtil; import com.example.material.util.ThemeUtil; import com.example.material.util.ViewUtil; import com.example.material.widget.ProgressView; import com.example.materialprogressdailogdesign.R; public class CircularProgressDrawable extends Drawable implements Animatable { private long mLastUpdateTime; private long mLastProgressStateTime; private long mLastRunStateTime; private int mProgressState; private static final int PROGRESS_STATE_HIDE = -1; private static final int PROGRESS_STATE_STRETCH = 0; private static final int PROGRESS_STATE_KEEP_STRETCH = 1; private static final int PROGRESS_STATE_SHRINK = 2; private static final int PROGRESS_STATE_KEEP_SHRINK = 3; private int mRunState = RUN_STATE_STOPPED; private static final int RUN_STATE_STOPPED = 0; private static final int RUN_STATE_STARTING = 1; private static final int RUN_STATE_STARTED = 2; private static final int RUN_STATE_RUNNING = 3; private static final int RUN_STATE_STOPPING = 4; private Paint mPaint; private RectF mRect; private float mStartAngle; private float mSweepAngle; private int mStrokeColorIndex; private int mPadding; private float mInitialAngle; private float mProgressPercent; private float mSecondaryProgressPercent; private float mMaxSweepAngle; private float mMinSweepAngle; private int mStrokeSize; private int[] mStrokeColors; private int mStrokeSecondaryColor; private boolean mReverse; private int mRotateDuration; private int mTransformDuration; private int mKeepDuration; private float mInStepPercent; private int[] mInColors; private int mInAnimationDuration; private int mOutAnimationDuration; private int mProgressMode; private Interpolator mTransformInterpolator; private CircularProgressDrawable(int padding, float initialAngle, float progressPercent, float secondaryProgressPercent, float maxSweepAngle, float minSweepAngle, int strokeSize, int[] strokeColors, int strokeSecondaryColor, boolean reverse, int rotateDuration, int transformDuration, int keepDuration, Interpolator transformInterpolator, int progressMode, int inAnimDuration, float inStepPercent, int[] inStepColors, int outAnimDuration){ mPadding = padding; mInitialAngle = initialAngle; setProgress(progressPercent); setSecondaryProgress(secondaryProgressPercent); mMaxSweepAngle = maxSweepAngle; mMinSweepAngle = minSweepAngle; mStrokeSize = strokeSize; mStrokeColors = strokeColors; mStrokeSecondaryColor = strokeSecondaryColor; mReverse = reverse; mRotateDuration = rotateDuration; mTransformDuration = transformDuration; mKeepDuration = keepDuration; mTransformInterpolator = transformInterpolator; mProgressMode = progressMode; mInAnimationDuration = inAnimDuration; mInStepPercent = inStepPercent; mInColors = inStepColors; mOutAnimationDuration = outAnimDuration; mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeJoin(Paint.Join.ROUND); mRect = new RectF(); } @Override public void draw(Canvas canvas) { switch (mProgressMode) { case ProgressView.MODE_DETERMINATE: drawDeterminate(canvas); break; case ProgressView.MODE_INDETERMINATE: drawIndeterminate(canvas); break; } } private void drawDeterminate(Canvas canvas){ Rect bounds = getBounds(); float radius = 0f; float size = 0f; if(mRunState == RUN_STATE_STARTING){ size = (float)mStrokeSize * Math.min(mInAnimationDuration, (SystemClock.uptimeMillis() - mLastRunStateTime)) / mInAnimationDuration; if(size > 0) radius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2 - mStrokeSize * 2 + size) / 2f; } else if(mRunState == RUN_STATE_STOPPING){ size = (float)mStrokeSize * Math.max(0, (mOutAnimationDuration - SystemClock.uptimeMillis() + mLastRunStateTime)) / mOutAnimationDuration; if(size > 0) radius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2 - mStrokeSize * 2 + size) / 2f; } else if(mRunState != RUN_STATE_STOPPED){ size = mStrokeSize; radius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2 - mStrokeSize) / 2f; } if(radius > 0){ float x = (bounds.left + bounds.right) / 2f; float y = (bounds.top + bounds.bottom) / 2f; mPaint.setStrokeWidth(size); mPaint.setStyle(Paint.Style.STROKE); if(mProgressPercent == 1f){ mPaint.setColor(mStrokeColors[0]); canvas.drawCircle(x, y, radius, mPaint); } else if(mProgressPercent == 0f){ mPaint.setColor(mStrokeSecondaryColor); canvas.drawCircle(x, y, radius, mPaint); } else{ float sweepAngle = (mReverse ? -360 : 360) * mProgressPercent; mRect.set(x - radius, y - radius, x + radius, y + radius); mPaint.setColor(mStrokeSecondaryColor); canvas.drawArc(mRect, mInitialAngle + sweepAngle, (mReverse ? -360 : 360) - sweepAngle, false, mPaint); mPaint.setColor(mStrokeColors[0]); canvas.drawArc(mRect, mInitialAngle, sweepAngle, false, mPaint); } } } private int getIndeterminateStrokeColor(){ if(mProgressState != PROGRESS_STATE_KEEP_SHRINK || mStrokeColors.length == 1) return mStrokeColors[mStrokeColorIndex]; float value = Math.max(0f, Math.min(1f, (float)(SystemClock.uptimeMillis() - mLastProgressStateTime) / mKeepDuration)); int prev_index = mStrokeColorIndex == 0 ? mStrokeColors.length - 1 : mStrokeColorIndex - 1; return ColorUtil.getMiddleColor(mStrokeColors[prev_index], mStrokeColors[mStrokeColorIndex], value); } private void drawIndeterminate(Canvas canvas){ if(mRunState == RUN_STATE_STARTING){ Rect bounds = getBounds(); float x = (bounds.left + bounds.right) / 2f; float y = (bounds.top + bounds.bottom) / 2f; float maxRadius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2) / 2f; float stepTime = 1f / (mInStepPercent * (mInColors.length + 2) + 1); float time = (float)(SystemClock.uptimeMillis() - mLastRunStateTime) / mInAnimationDuration; float steps = time / stepTime; float outerRadius = 0f; float innerRadius = 0f; for(int i = (int)Math.floor(steps); i >= 0; i--){ innerRadius = outerRadius; outerRadius = Math.min(1f, (steps - i) * mInStepPercent) * maxRadius; if(i >= mInColors.length) continue; if(innerRadius == 0){ mPaint.setColor(mInColors[i]); mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(x, y, outerRadius, mPaint); } else if(outerRadius > innerRadius){ float radius = (innerRadius + outerRadius) / 2; mRect.set(x - radius, y - radius, x + radius, y + radius); mPaint.setStrokeWidth(outerRadius - innerRadius); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mInColors[i]); canvas.drawCircle(x, y, radius, mPaint); } else break; } if(mProgressState == PROGRESS_STATE_HIDE){ if(steps >= 1 / mInStepPercent || time >= 1) resetAnimation(); } else{ float radius = maxRadius - mStrokeSize / 2f; mRect.set(x - radius, y - radius, x + radius, y + radius); mPaint.setStrokeWidth(mStrokeSize); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(getIndeterminateStrokeColor()); canvas.drawArc(mRect, mStartAngle, mSweepAngle, false, mPaint); } } else if(mRunState == RUN_STATE_STOPPING){ float size = (float)mStrokeSize * Math.max(0, (mOutAnimationDuration - SystemClock.uptimeMillis() + mLastRunStateTime)) / mOutAnimationDuration; if(size > 0){ Rect bounds = getBounds(); float radius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2 - mStrokeSize * 2 + size) / 2f; float x = (bounds.left + bounds.right) / 2f; float y = (bounds.top + bounds.bottom) / 2f; mRect.set(x - radius, y - radius, x + radius, y + radius); mPaint.setStrokeWidth(size); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(getIndeterminateStrokeColor()); canvas.drawArc(mRect, mStartAngle, mSweepAngle, false, mPaint); } } else if(mRunState != RUN_STATE_STOPPED){ Rect bounds = getBounds(); float radius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2 - mStrokeSize) / 2f; float x = (bounds.left + bounds.right) / 2f; float y = (bounds.top + bounds.bottom) / 2f; mRect.set(x - radius, y - radius, x + radius, y + radius); mPaint.setStrokeWidth(mStrokeSize); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(getIndeterminateStrokeColor()); canvas.drawArc(mRect, mStartAngle, mSweepAngle, false, mPaint); } } @Override public void setAlpha(int alpha) { mPaint.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } public int getProgressMode(){ return mProgressMode; } public float getProgress(){ return mProgressPercent; } public float getSecondaryProgress(){ return mSecondaryProgressPercent; } public void setProgress(float percent){ percent = Math.min(1f, Math.max(0f, percent)); if(mProgressPercent != percent){ mProgressPercent = percent; if(isRunning()) invalidateSelf(); else if(mProgressPercent != 0f) start(); } } public void setSecondaryProgress(float percent){ percent = Math.min(1f, Math.max(0f, percent)); if(mSecondaryProgressPercent != percent){ mSecondaryProgressPercent = percent; if(isRunning()) invalidateSelf(); else if(mSecondaryProgressPercent != 0f) start(); } } //Animation: based on http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/ private void resetAnimation(){ mLastUpdateTime = SystemClock.uptimeMillis(); mLastProgressStateTime = mLastUpdateTime; mStartAngle = mInitialAngle; mStrokeColorIndex = 0; mSweepAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle; mProgressState = PROGRESS_STATE_STRETCH; } @Override public void start() { start(mInAnimationDuration > 0); } @Override public void stop() { stop(mOutAnimationDuration > 0); } private void start(boolean withAnimation){ if(isRunning()) return; if(withAnimation){ mRunState = RUN_STATE_STARTING; mLastRunStateTime = SystemClock.uptimeMillis(); mProgressState = PROGRESS_STATE_HIDE; } else resetAnimation(); scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } private void stop(boolean withAnimation){ if(!isRunning()) return; if(withAnimation){ mLastRunStateTime = SystemClock.uptimeMillis(); if(mRunState == RUN_STATE_STARTED){ scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } mRunState = RUN_STATE_STOPPING; } else{ mRunState = RUN_STATE_STOPPED; unscheduleSelf(mUpdater); invalidateSelf(); } } @Override public boolean isRunning() { return mRunState != RUN_STATE_STOPPED; } @Override public void scheduleSelf(Runnable what, long when) { if(mRunState == RUN_STATE_STOPPED) mRunState = mInAnimationDuration > 0 ? RUN_STATE_STARTING : RUN_STATE_RUNNING; super.scheduleSelf(what, when); } private final Runnable mUpdater = new Runnable() { @Override public void run() { update(); } }; private void update(){ switch (mProgressMode) { case ProgressView.MODE_DETERMINATE: updateDeterminate(); break; case ProgressView.MODE_INDETERMINATE: updateIndeterminate(); break; } } private void updateDeterminate(){ long curTime = SystemClock.uptimeMillis(); if(mRunState == RUN_STATE_STARTING){ if(curTime - mLastRunStateTime > mInAnimationDuration){ mRunState = RUN_STATE_STARTED; return; } } else if(mRunState == RUN_STATE_STOPPING){ if(curTime - mLastRunStateTime > mOutAnimationDuration){ stop(false); return; } } if(isRunning()) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } private void updateIndeterminate(){ //update animation long curTime = SystemClock.uptimeMillis(); float rotateOffset = (curTime - mLastUpdateTime) * 360f / mRotateDuration; if(mReverse) rotateOffset = -rotateOffset; mLastUpdateTime = curTime; switch (mProgressState) { case PROGRESS_STATE_STRETCH: if(mTransformDuration <= 0){ mSweepAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle; mProgressState = PROGRESS_STATE_KEEP_STRETCH; mStartAngle += rotateOffset; mLastProgressStateTime = curTime; } else{ float value = (curTime - mLastProgressStateTime) / (float)mTransformDuration; float maxAngle = mReverse ? -mMaxSweepAngle : mMaxSweepAngle; float minAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle; mStartAngle += rotateOffset; mSweepAngle = mTransformInterpolator.getInterpolation(value) * (maxAngle - minAngle) + minAngle; if(value > 1f){ mSweepAngle = maxAngle; mProgressState = PROGRESS_STATE_KEEP_STRETCH; mLastProgressStateTime = curTime; } } break; case PROGRESS_STATE_KEEP_STRETCH: mStartAngle += rotateOffset; if(curTime - mLastProgressStateTime > mKeepDuration){ mProgressState = PROGRESS_STATE_SHRINK; mLastProgressStateTime = curTime; } break; case PROGRESS_STATE_SHRINK: if(mTransformDuration <= 0){ mSweepAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle; mProgressState = PROGRESS_STATE_KEEP_SHRINK; mStartAngle += rotateOffset; mLastProgressStateTime = curTime; mStrokeColorIndex = (mStrokeColorIndex + 1) % mStrokeColors.length; } else{ float value = (curTime - mLastProgressStateTime) / (float)mTransformDuration; float maxAngle = mReverse ? -mMaxSweepAngle : mMaxSweepAngle; float minAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle; float newSweepAngle = (1f - mTransformInterpolator.getInterpolation(value)) * (maxAngle - minAngle) + minAngle; mStartAngle += rotateOffset + mSweepAngle - newSweepAngle; mSweepAngle = newSweepAngle; if(value > 1f){ mSweepAngle = minAngle; mProgressState = PROGRESS_STATE_KEEP_SHRINK; mLastProgressStateTime = curTime; mStrokeColorIndex = (mStrokeColorIndex + 1) % mStrokeColors.length; } } break; case PROGRESS_STATE_KEEP_SHRINK: mStartAngle += rotateOffset; if(curTime - mLastProgressStateTime > mKeepDuration){ mProgressState = PROGRESS_STATE_STRETCH; mLastProgressStateTime = curTime; } break; } if(mRunState == RUN_STATE_STARTING){ if(curTime - mLastRunStateTime > mInAnimationDuration){ mRunState = RUN_STATE_RUNNING; if(mProgressState == PROGRESS_STATE_HIDE) resetAnimation(); } } else if(mRunState == RUN_STATE_STOPPING){ if(curTime - mLastRunStateTime > mOutAnimationDuration){ stop(false); return; } } if (isRunning()) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } public static class Builder{ private int mPadding; private float mInitialAngle; private float mProgressPercent; private float mSecondaryProgressPercent; private float mMaxSweepAngle; private float mMinSweepAngle; private int mStrokeSize; private int[] mStrokeColors; private int mStrokeSecondaryColor; private boolean mReverse; private int mRotateDuration; private int mTransformDuration; private int mKeepDuration; private Interpolator mTransformInterpolator; private int mProgressMode; private float mInStepPercent; private int[] mInColors; private int mInAnimationDuration; private int mOutAnimationDuration; public Builder(){} public Builder(Context context, int defStyleRes){ this(context, null, 0, defStyleRes); } public Builder(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularProgressDrawable, defStyleAttr, defStyleRes); int resId; padding(a.getDimensionPixelSize(R.styleable.CircularProgressDrawable_cpd_padding, 0)); initialAngle(a.getInteger(R.styleable.CircularProgressDrawable_cpd_initialAngle, 0)); progressPercent(a.getFloat(R.styleable.CircularProgressDrawable_pv_progress, 0)); secondaryProgressPercent(a.getFloat(R.styleable.CircularProgressDrawable_pv_secondaryProgress, 0)); maxSweepAngle(a.getInteger(R.styleable.CircularProgressDrawable_cpd_maxSweepAngle, 270)); minSweepAngle(a.getInteger(R.styleable.CircularProgressDrawable_cpd_minSweepAngle, 1)); strokeSize(a.getDimensionPixelSize(R.styleable.CircularProgressDrawable_cpd_strokeSize, ThemeUtil.dpToPx(context, 4))); strokeColors(a.getColor(R.styleable.CircularProgressDrawable_cpd_strokeColor, ThemeUtil.colorPrimary(context, 0xFF000000))); if((resId = a.getResourceId(R.styleable.CircularProgressDrawable_cpd_strokeColors, 0)) != 0){ TypedArray ta = context.getResources().obtainTypedArray(resId); int[] colors = new int[ta.length()]; for(int j = 0; j < ta.length(); j++) colors[j] = ta.getColor(j, 0); ta.recycle(); strokeColors(colors); } strokeSecondaryColor(a.getColor(R.styleable.CircularProgressDrawable_cpd_strokeSecondaryColor, 0)); reverse(a.getBoolean(R.styleable.CircularProgressDrawable_cpd_reverse, false)); rotateDuration(a.getInteger(R.styleable.CircularProgressDrawable_cpd_rotateDuration, context.getResources().getInteger(android.R.integer.config_longAnimTime))); transformDuration(a.getInteger(R.styleable.CircularProgressDrawable_cpd_transformDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime))); keepDuration(a.getInteger(R.styleable.CircularProgressDrawable_cpd_keepDuration, context.getResources().getInteger(android.R.integer.config_shortAnimTime))); if((resId = a.getResourceId(R.styleable.CircularProgressDrawable_cpd_transformInterpolator, 0)) != 0) transformInterpolator(AnimationUtils.loadInterpolator(context, resId)); progressMode(a.getInteger(R.styleable.CircularProgressDrawable_pv_progressMode, ProgressView.MODE_INDETERMINATE)); inAnimDuration(a.getInteger(R.styleable.CircularProgressDrawable_cpd_inAnimDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime))); if((resId = a.getResourceId(R.styleable.CircularProgressDrawable_cpd_inStepColors, 0)) != 0){ TypedArray ta = context.getResources().obtainTypedArray(resId); int[] colors = new int[ta.length()]; for(int j = 0; j < ta.length(); j++) colors[j] = ta.getColor(j, 0); ta.recycle(); inStepColors(colors); } inStepPercent(a.getFloat(R.styleable.CircularProgressDrawable_cpd_inStepPercent, 0.5f)); outAnimDuration(a.getInteger(R.styleable.CircularProgressDrawable_cpd_outAnimDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime))); a.recycle(); } public CircularProgressDrawable build(){ if(mStrokeColors == null) mStrokeColors = new int[]{0xFF0099FF}; if(mInColors == null && mInAnimationDuration > 0) mInColors = new int[]{0xFFB5D4FF, 0xFFDEEAFC, 0xFFFAFFFE}; if(mTransformInterpolator == null) mTransformInterpolator = new DecelerateInterpolator(); return new CircularProgressDrawable(mPadding, mInitialAngle, mProgressPercent, mSecondaryProgressPercent, mMaxSweepAngle, mMinSweepAngle, mStrokeSize, mStrokeColors, mStrokeSecondaryColor, mReverse, mRotateDuration, mTransformDuration, mKeepDuration, mTransformInterpolator, mProgressMode, mInAnimationDuration, mInStepPercent, mInColors, mOutAnimationDuration); } public Builder padding(int padding){ mPadding = padding; return this; } public Builder initialAngle(float angle){ mInitialAngle = angle; return this; } public Builder progressPercent(float percent){ mProgressPercent = percent; return this; } public Builder secondaryProgressPercent(float percent){ mSecondaryProgressPercent = percent; return this; } public Builder maxSweepAngle(float angle){ mMaxSweepAngle = angle; return this; } public Builder minSweepAngle(float angle){ mMinSweepAngle = angle; return this; } public Builder strokeSize(int strokeSize){ mStrokeSize = strokeSize; return this; } public Builder strokeColors(int... strokeColors){ mStrokeColors = strokeColors; return this; } public Builder strokeSecondaryColor(int color){ mStrokeSecondaryColor = color; return this; } public Builder reverse(boolean reverse){ mReverse = reverse; return this; } public Builder reverse(){ return reverse(true); } public Builder rotateDuration(int duration){ mRotateDuration = duration; return this; } public Builder transformDuration(int duration){ mTransformDuration = duration; return this; } public Builder keepDuration(int duration){ mKeepDuration = duration; return this; } public Builder transformInterpolator(Interpolator interpolator){ mTransformInterpolator = interpolator; return this; } public Builder progressMode(int mode){ mProgressMode = mode; return this; } public Builder inAnimDuration(int duration){ mInAnimationDuration = duration; return this; } public Builder inStepPercent(float percent){ mInStepPercent = percent; return this; } public Builder inStepColors(int... colors){ mInColors = colors; return this; } public Builder outAnimDuration(int duration){ mOutAnimationDuration = duration; return this; } } }
—> Run Your Code.
Leave a Reply