http://blog.csdn.net/wangjinyu501/article/details/20456761
http://blog.csdn.net/wangjinyu501/article/details/20456761
http://blog.csdn.net/wangjinyu501/article/details/20456761
http://blog.csdn.net/wangjinyu501/article/details/20456761
分类:
版权声明:本文为博主原创文章,未经博主允许不得转载。
版本:2.0
日期:2014.4.14 2014.5.7
版权:© 2014 kince 转载注明出处
方式一
系统自带的SeekBar样式是水平的,如果需求一个垂直方向的效果就需要自定义了。原理很简单,即定义一个类继承于SeekBar,并在OnDraw方法里面旋转一下视图。
代码如下:
- package android.widget;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- public class VerticalSeekBar extends SeekBar {
- public VerticalSeekBar(Context context) {
- super(context);
- }
- public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- public VerticalSeekBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(h, w, oldh, oldw);
- }
- @Override
- protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(heightMeasureSpec, widthMeasureSpec);
- setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
- }
- protected void onDraw(Canvas c) {
- //将SeekBar转转90度
- c.rotate(-90);
- //将旋转后的视图移动回来
- c.translate(-getHeight(),0);
- Log.i("getHeight()",getHeight()+"");
- super.onDraw(c);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!isEnabled()) {
- return false;
- }
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_UP:
- int i=0;
- //获取滑动的距离
- i=getMax() - (int) (getMax() * event.getY() / getHeight());
- //设置进度
- setProgress(i);
- Log.i("Progress",getProgress()+"");
- //每次拖动SeekBar都会调用
- onSizeChanged(getWidth(), getHeight(), 0, 0);
- Log.i("getWidth()",getWidth()+"");
- Log.i("getHeight()",getHeight()+"");
- break;
- case MotionEvent.ACTION_CANCEL:
- break;
- }
- return true;
- }
- }
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:gravity="center"
- android:background="@android:color/white"
- android:orientation="horizontal" >
- <android.widget.VerticalSeekBar_Reverse
- android:id="@+id/seekbar_reverse"
- android:layout_width="wrap_content"
- android:layout_height="450dip"
- android:layout_marginRight="30dip" />
- <TextView
- android:id="@+id/reverse_sb_progresstext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/seekbar_reverse"
- android:gravity="center" />
- <android.widget.VerticalSeekBar
- android:id="@+id/vertical_Seekbar"
- android:layout_width="wrap_content"
- android:layout_height="450dip"
- android:layout_toRightOf="@+id/seekbar_reverse" />
- <TextView
- android:id="@+id/vertical_sb_progresstext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/vertical_Seekbar"
- android:layout_toRightOf="@+id/seekbar_reverse"
- android:gravity="center" />
- </RelativeLayout>
方式二
还有一种方式就是对系统的ProgressBar进行修改,代码如下:
- /*
- * Copyright (C) 2011 The MusicMod Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.joggingTunes.android.activities;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Rect;
- import android.graphics.drawable.BitmapDrawable;
- import android.graphics.drawable.ClipDrawable;
- import android.graphics.drawable.Drawable;
- import android.graphics.drawable.LayerDrawable;
- import android.graphics.drawable.ShapeDrawable;
- import android.graphics.drawable.StateListDrawable;
- import android.graphics.drawable.shapes.RoundRectShape;
- import android.graphics.drawable.shapes.Shape;
- import android.util.AttributeSet;
- import android.view.Gravity;
- import android.view.View;
- import android.view.ViewDebug;
- import android.view.ViewParent;
- import android.widget.RemoteViews.RemoteView;
- import android.os.Parcel;
- import android.os.Parcelable;
- @RemoteView
- public class VerticalProgressBar extends View {
- private static final int MAX_LEVEL = 10000;
- int mMinWidth;
- int mMaxWidth;
- int mMinHeight;
- int mMaxHeight;
- private int mProgress;
- private int mSecondaryProgress;
- private int mMax;
- private Drawable mProgressDrawable;
- private Drawable mCurrentDrawable;
- Bitmap mSampleTile;
- private boolean mNoInvalidate;
- private RefreshProgressRunnable mRefreshProgressRunnable;
- private long mUiThreadId;
- private boolean mInDrawing;
- protected int mScrollX;
- protected int mScrollY;
- protected int mPaddingLeft;
- protected int mPaddingRight;
- protected int mPaddingTop;
- protected int mPaddingBottom;
- protected ViewParent mParent;
- /**
- * Create a new progress bar with range 0...100 and initial progress of 0.
- *
- * @param context
- * the application environment
- */
- public VerticalProgressBar(Context context) {
- this(context, null);
- }
- public VerticalProgressBar(Context context, AttributeSet attrs) {
- this(context, attrs, android.R.attr.progressBarStyle);
- }
- public VerticalProgressBar(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mUiThreadId = Thread.currentThread().getId();
- initProgressBar();
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.ProgressBar, defStyle, 0);
- mNoInvalidate = true;
- Drawable drawable = a
- .getDrawable(R.styleable.ProgressBar_android_progressDrawable);
- if (drawable != null) {
- drawable = tileify(drawable, false);
- // Calling this method can set mMaxHeight, make sure the
- // corresponding
- // XML attribute for mMaxHeight is read after calling this method
- setProgressDrawable(drawable);
- }
- mMinWidth = a.getDimensionPixelSize(
- R.styleable.ProgressBar_android_minWidth, mMinWidth);
- mMaxWidth = a.getDimensionPixelSize(
- R.styleable.ProgressBar_android_maxWidth, mMaxWidth);
- mMinHeight = a.getDimensionPixelSize(
- R.styleable.ProgressBar_android_minHeight, mMinHeight);
- mMaxHeight = a.getDimensionPixelSize(
- R.styleable.ProgressBar_android_maxHeight, mMaxHeight);
- setMax(a.getInt(R.styleable.ProgressBar_android_max, mMax));
- setProgress(a.getInt(R.styleable.ProgressBar_android_progress,
- mProgress));
- setSecondaryProgress(a.getInt(
- R.styleable.ProgressBar_android_secondaryProgress,
- mSecondaryProgress));
- mNoInvalidate = false;
- a.recycle();
- }
- /**
- * Converts a drawable to a tiled version of itself. It will recursively
- * traverse layer and state list drawables.
- */
- private Drawable tileify(Drawable drawable, boolean clip) {
- if (drawable instanceof LayerDrawable) {
- LayerDrawable background = (LayerDrawable) drawable;
- final int N = background.getNumberOfLayers();
- Drawable[] outDrawables = new Drawable[N];
- for (int i = 0; i < N; i++) {
- int id = background.getId(i);
- outDrawables[i] = tileify(
- background.getDrawable(i),
- (id == android.R.id.progress || id == android.R.id.secondaryProgress));
- }
- LayerDrawable newBg = new LayerDrawable(outDrawables);
- for (int i = 0; i < N; i++) {
- newBg.setId(i, background.getId(i));
- }
- return newBg;
- } else if (drawable instanceof StateListDrawable) {
- StateListDrawable out = new StateListDrawable();
- return out;
- } else if (drawable instanceof BitmapDrawable) {
- final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
- if (mSampleTile == null) {
- mSampleTile = tileBitmap;
- }
- final ShapeDrawable shapeDrawable = new ShapeDrawable(
- getDrawableShape());
- return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
- ClipDrawable.HORIZONTAL) : shapeDrawable;
- }
- return drawable;
- }
- Shape getDrawableShape() {
- final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
- return new RoundRectShape(roundedCorners, null, null);
- }
- /**
- * <p>
- * Initialize the progress bar's default values:
- * </p>
- * <ul>
- * <li>progress = 0</li>
- * <li>max = 100</li>
- * </ul>
- */
- private void initProgressBar() {
- mMax = 100;
- mProgress = 0;
- mSecondaryProgress = 0;
- mMinWidth = 24;
- mMaxWidth = 48;
- mMinHeight = 24;
- mMaxHeight = 48;
- }
- /**
- * <p>
- * Get the drawable used to draw the progress bar in progress mode.
- * </p>
- *
- * @return a {@link android.graphics.drawable.Drawable} instance
- *
- * @see #setProgressDrawable(android.graphics.drawable.Drawable)
- */
- public Drawable getProgressDrawable() {
- return mProgressDrawable;
- }
- /**
- * <p>
- * Define the drawable used to draw the progress bar in progress mode.
- * </p>
- *
- * @param d
- * the new drawable
- *
- * @see #getProgressDrawable()
- */
- public void setProgressDrawable(Drawable d) {
- if (d != null) {
- d.setCallback(this);
- // Make sure the ProgressBar is always tall enough
- int drawableHeight = d.getMinimumHeight();
- if (mMaxHeight < drawableHeight) {
- mMaxHeight = drawableHeight;
- requestLayout();
- }
- }
- mProgressDrawable = d;
- mCurrentDrawable = d;
- postInvalidate();
- }
- /**
- * @return The drawable currently used to draw the progress bar
- */
- Drawable getCurrentDrawable() {
- return mCurrentDrawable;
- }
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return who == mProgressDrawable || super.verifyDrawable(who);
- }
- @Override
- public void postInvalidate() {
- if (!mNoInvalidate) {
- super.postInvalidate();
- }
- }
- private class RefreshProgressRunnable implements Runnable {
- private int mId;
- private int mProgress;
- private boolean mFromUser;
- RefreshProgressRunnable(int id, int progress, boolean fromUser) {
- mId = id;
- mProgress = progress;
- mFromUser = fromUser;
- }
- public void run() {
- doRefreshProgress(mId, mProgress, mFromUser);
- // Put ourselves back in the cache when we are done
- mRefreshProgressRunnable = this;
- }
- public void setup(int id, int progress, boolean fromUser) {
- mId = id;
- mProgress = progress;
- mFromUser = fromUser;
- }
- }
- private synchronized void doRefreshProgress(int id, int progress,
- boolean fromUser) {
- float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
- final Drawable d = mCurrentDrawable;
- if (d != null) {
- Drawable progressDrawable = null;
- if (d instanceof LayerDrawable) {
- progressDrawable = ((LayerDrawable) d)
- .findDrawableByLayerId(id);
- }
- final int level = (int) (scale * MAX_LEVEL);
- (progressDrawable != null ? progressDrawable : d).setLevel(level);
- } else {
- invalidate();
- }
- if (id == android.R.id.progress) {
- onProgressRefresh(scale, fromUser);
- }
- }
- void onProgressRefresh(float scale, boolean fromUser) {
- }
- private synchronized void refreshProgress(int id, int progress,
- boolean fromUser) {
- if (mUiThreadId == Thread.currentThread().getId()) {
- doRefreshProgress(id, progress, fromUser);
- } else {
- RefreshProgressRunnable r;
- if (mRefreshProgressRunnable != null) {
- // Use cached RefreshProgressRunnable if available
- r = mRefreshProgressRunnable;
- // Uncache it
- mRefreshProgressRunnable = null;
- r.setup(id, progress, fromUser);
- } else {
- // Make a new one
- r = new RefreshProgressRunnable(id, progress, fromUser);
- }
- post(r);
- }
- }
- /**
- * <p>
- * Set the current progress to the specified value.
- * </p>
- *
- * @param progress
- * the new progress, between 0 and {@link #getMax()}
- *
- * @see #getProgress()
- * @see #incrementProgressBy(int)
- */
- public synchronized void setProgress(int progress) {
- setProgress(progress, false);
- }
- synchronized void setProgress(int progress, boolean fromUser) {
- if (progress < 0) {
- progress = 0;
- }
- if (progress > mMax) {
- progress = mMax;
- }
- if (progress != mProgress) {
- mProgress = progress;
- refreshProgress(android.R.id.progress, mProgress, fromUser);
- }
- }
- /**
- * <p>
- * Set the current secondary progress to the specified value.
- * </p>
- *
- * @param secondaryProgress
- * the new secondary progress, between 0 and {@link #getMax()}
- * @see #getSecondaryProgress()
- * @see #incrementSecondaryProgressBy(int)
- */
- public synchronized void setSecondaryProgress(int secondaryProgress) {
- if (secondaryProgress < 0) {
- secondaryProgress = 0;
- }
- if (secondaryProgress > mMax) {
- secondaryProgress = mMax;
- }
- if (secondaryProgress != mSecondaryProgress) {
- mSecondaryProgress = secondaryProgress;
- refreshProgress(android.R.id.secondaryProgress, mSecondaryProgress,
- false);
- }
- }
- /**
- * <p>
- * Get the progress bar's current level of progress.
- * </p>
- *
- * @return the current progress, between 0 and {@link #getMax()}
- *
- * @see #setProgress(int)
- * @see #setMax(int)
- * @see #getMax()
- */
- @ViewDebug.ExportedProperty
- public synchronized int getProgress() {
- return mProgress;
- }
- /**
- * <p>
- * Get the progress bar's current level of secondary progress.
- * </p>
- *
- * @return the current secondary progress, between 0 and {@link #getMax()}
- *
- * @see #setSecondaryProgress(int)
- * @see #setMax(int)
- * @see #getMax()
- */
- @ViewDebug.ExportedProperty
- public synchronized int getSecondaryProgress() {
- return mSecondaryProgress;
- }
- /**
- * <p>
- * Return the upper limit of this progress bar's range.
- * </p>
- *
- * @return a positive integer
- *
- * @see #setMax(int)
- * @see #getProgress()
- * @see #getSecondaryProgress()
- */
- @ViewDebug.ExportedProperty
- public synchronized int getMax() {
- return mMax;
- }
- /**
- * <p>
- * Set the range of the progress bar to 0...<tt>max</tt>.
- * </p>
- *
- * @param max
- * the upper range of this progress bar
- *
- * @see #getMax()
- * @see #setProgress(int)
- * @see #setSecondaryProgress(int)
- */
- public synchronized void setMax(int max) {
- if (max < 0) {
- max = 0;
- }
- if (max != mMax) {
- mMax = max;
- postInvalidate();
- if (mProgress > max) {
- mProgress = max;
- refreshProgress(android.R.id.progress, mProgress, false);
- }
- }
- }
- /**
- * <p>
- * Increase the progress bar's progress by the specified amount.
- * </p>
- *
- * @param diff
- * the amount by which the progress must be increased
- *
- * @see #setProgress(int)
- */
- public synchronized final void incrementProgressBy(int diff) {
- setProgress(mProgress + diff);
- }
- /**
- * <p>
- * Increase the progress bar's secondary progress by the specified amount.
- * </p>
- *
- * @param diff
- * the amount by which the secondary progress must be increased
- *
- * @see #setSecondaryProgress(int)
- */
- public synchronized final void incrementSecondaryProgressBy(int diff) {
- setSecondaryProgress(mSecondaryProgress + diff);
- }
- @Override
- public void setVisibility(int v) {
- if (getVisibility() != v) {
- super.setVisibility(v);
- }
- }
- @Override
- public void invalidateDrawable(Drawable dr) {
- if (!mInDrawing) {
- if (verifyDrawable(dr)) {
- final Rect dirty = dr.getBounds();
- final int scrollX = mScrollX + mPaddingLeft;
- final int scrollY = mScrollY + mPaddingTop;
- invalidate(dirty.left + scrollX, dirty.top + scrollY,
- dirty.right + scrollX, dirty.bottom + scrollY);
- } else {
- super.invalidateDrawable(dr);
- }
- }
- }
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- // onDraw will translate the canvas so we draw starting at 0,0
- int right = w - mPaddingRight - mPaddingLeft;
- int bottom = h - mPaddingBottom - mPaddingTop;
- if (mProgressDrawable != null) {
- mProgressDrawable.setBounds(0, 0, right, bottom);
- }
- }
- @Override
- protected synchronized void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- Drawable d = mCurrentDrawable;
- if (d != null) {
- // Translate canvas so a indeterminate circular progress bar with
- // padding
- // rotates properly in its animation
- canvas.save();
- canvas.translate(mPaddingLeft, mPaddingTop);
- d.draw(canvas);
- canvas.restore();
- }
- }
- @Override
- protected synchronized void onMeasure(int widthMeasureSpec,
- int heightMeasureSpec) {
- Drawable d = mCurrentDrawable;
- int dw = 0;
- int dh = 0;
- if (d != null) {
- dw = Math
- .max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
- dh = Math.max(mMinHeight, Math.min(mMaxHeight, d
- .getIntrinsicHeight()));
- }
- dw += mPaddingLeft + mPaddingRight;
- dh += mPaddingTop + mPaddingBottom;
- setMeasuredDimension(resolveSize(dw, widthMeasureSpec), resolveSize(dh,
- heightMeasureSpec));
- }
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
- int[] state = getDrawableState();
- if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
- mProgressDrawable.setState(state);
- }
- }
- static class SavedState extends BaseSavedState {
- int progress;
- int secondaryProgress;
- /**
- * Constructor called from {@link ProgressBar#onSaveInstanceState()}
- */
- SavedState(Parcelable superState) {
- super(superState);
- }
- /**
- * Constructor called from {@link #CREATOR}
- */
- private SavedState(Parcel in) {
- super(in);
- progress = in.readInt();
- secondaryProgress = in.readInt();
- }
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeInt(progress);
- out.writeInt(secondaryProgress);
- }
- public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
- @Override
- public Parcelable onSaveInstanceState() {
- // Force our ancestor class to save its state
- Parcelable superState = super.onSaveInstanceState();
- SavedState ss = new SavedState(superState);
- ss.progress = mProgress;
- ss.secondaryProgress = mSecondaryProgress;
- return ss;
- }
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- setProgress(ss.progress);
- setSecondaryProgress(ss.secondaryProgress);
- }
- }
方式三
还是从源码入手,找到设置ProgressBar样式的progress_horizontal.xml文件,
为什么shape外面要包一层clip呢,官方文档解释是clipdrawable是可以自我复制的,来看看定义
android:clipOrientation有两个属性,默认为horizontal,android:gravity有两个属性,默认为left。那我们试试改成vertical和bottom会有什么效果,新建一个progress_vertical.xml,把源码progress_horizontal.xml的内容复制过来,这里去掉了secondaryProgress,修改了clip,shape的渐变中心centerY改为centerX
布局中android:progressDrawable="@drawable/progress_vertical",ok,搞定。
- <item android:id="@android:id/progress">
- <clip>
- <shape>
- <corners android:radius="5dip" />
- <gradient
- android:startColor="#ffffd300"
- android:centerColor="#ffffb600"
- android:centerY="0.75"
- android:endColor="#ffffcb00"
- android:angle="270"
- />
- </shape>
- </clip>
- </item>
- <?xml version="1.0" encoding="utf-8"?>
- <clip
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/drawable_resource"
- android:clipOrientation=["horizontal" | "vertical"]
- android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
- "fill_vertical" | "center_horizontal" | "fill_horizontal" |
- "center" | "fill" | "clip_vertical" | "clip_horizontal"] />
- <item android:id="@android:id/progress">
- <clip
- android:clipOrientation="vertical"
- android:gravity = "bottom">
- <shape>
- <corners android:radius="5dip" />
- <gradient
- android:startColor="#ffffd300"
- android:centerColor="#ffffb600"
- android:centerX="0.75"
- android:endColor="#ffffcb00"
- android:angle="90"
- />
- </shape>
- </clip>
- </item>
代码下载(方式一代码)