版本: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布局文件:

<?xml version="1.0" encoding="utf-8"?>                
   Android 自定义UI-垂直方向的SeekBar_第1张图片 方式二   还有一种方式就是对系统的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;@RemoteViewpublic 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 methodsetProgressDrawable(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);}/** * 

* Initialize the progress bar's default values: *

*
    *
  • progress = 0
  • *
  • max = 100
  • *
*/private void initProgressBar() {mMax = 100;mProgress = 0;mSecondaryProgress = 0;mMinWidth = 24;mMaxWidth = 48;mMinHeight = 24;mMaxHeight = 48;}/** *

* Get the drawable used to draw the progress bar in progress mode. *

* * @return a {@link android.graphics.drawable.Drawable} instance * * @see #setProgressDrawable(android.graphics.drawable.Drawable) */public Drawable getProgressDrawable() {return mProgressDrawable;}/** *

* Define the drawable used to draw the progress bar in progress mode. *

* * @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 enoughint 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;}@Overrideprotected boolean verifyDrawable(Drawable who) {return who == mProgressDrawable || super.verifyDrawable(who);}@Overridepublic 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 donemRefreshProgressRunnable = 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 availabler = mRefreshProgressRunnable;// Uncache itmRefreshProgressRunnable = null;r.setup(id, progress, fromUser);} else {// Make a new oner = new RefreshProgressRunnable(id, progress, fromUser);}post(r);}}/** *

* Set the current progress to the specified value. *

* * @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);}}/** *

* Set the current secondary progress to the specified value. *

* * @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);}}/** *

* Get the progress bar's current level of progress. *

* * @return the current progress, between 0 and {@link #getMax()} * * @see #setProgress(int) * @see #setMax(int) * @see #getMax() */@ViewDebug.ExportedPropertypublic synchronized int getProgress() {return mProgress;}/** *

* Get the progress bar's current level of secondary progress. *

* * @return the current secondary progress, between 0 and {@link #getMax()} * * @see #setSecondaryProgress(int) * @see #setMax(int) * @see #getMax() */@ViewDebug.ExportedPropertypublic synchronized int getSecondaryProgress() {return mSecondaryProgress;}/** *

* Return the upper limit of this progress bar's range. *

* * @return a positive integer * * @see #setMax(int) * @see #getProgress() * @see #getSecondaryProgress() */@ViewDebug.ExportedPropertypublic synchronized int getMax() {return mMax;}/** *

* Set the range of the progress bar to 0...max. *

* * @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);}}}/** *

* Increase the progress bar's progress by the specified amount. *

* * @param diff * the amount by which the progress must be increased * * @see #setProgress(int) */public synchronized final void incrementProgressBy(int diff) {setProgress(mProgress + diff);}/** *

* Increase the progress bar's secondary progress by the specified amount. *

* * @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);}@Overridepublic void setVisibility(int v) {if (getVisibility() != v) {super.setVisibility(v);}}@Overridepublic 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);}}}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {// onDraw will translate the canvas so we draw starting at 0,0int right = w - mPaddingRight - mPaddingLeft;int bottom = h - mPaddingBottom - mPaddingTop;if (mProgressDrawable != null) {mProgressDrawable.setBounds(0, 0, right, bottom);}}@Overrideprotected 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 animationcanvas.save();canvas.translate(mPaddingLeft, mPaddingTop);d.draw(canvas);canvas.restore();}}@Overrideprotected 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));}@Overrideprotected 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();}@Overridepublic void writeToParcel(Parcel out, int flags) {super.writeToParcel(out, flags);out.writeInt(progress);out.writeInt(secondaryProgress);}public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {public SavedState createFromParcel(Parcel in) {return new SavedState(in);}public SavedState[] newArray(int size) {return new SavedState[size];}};}@Overridepublic Parcelable onSaveInstanceState() {// Force our ancestor class to save its stateParcelable superState = super.onSaveInstanceState();SavedState ss = new SavedState(superState);ss.progress = mProgress;ss.secondaryProgress = mSecondaryProgress;return ss;}@Overridepublic 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是可以自我复制的,来看看定义
 <?xml version="1.0" encoding="utf-8"?>
  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,搞定。   代码下载(方式一代码)
  推荐博文: Android Canvas编程:对rotate()和translate()两个方法的研究

更多相关文章

  1. 【Android笔记】Android的三种网络通信方式
  2. android开发数据存储方式
  3. emulator找不到AVD解决方式
  4. repo sync同步Android 源代码下载到99%出错
  5. Android四种存储方式 sharedpreference,file,SQlite,contentprov
  6. android添加文件打开方式以及参数传递
  7. 【Android Studio快捷键】之代码提示

随机推荐

  1. Qt for Android(安卓)拉起微信登录、分享
  2. Android(安卓)API Guides---App Manifest
  3. Android应用优化之内存概念
  4. Android跨进程通信
  5. Delphi XE5 for android 调用Java类库必
  6. Android如何实现ListView的Item松开渐变
  7. android java.lang.SecurityException: P
  8. Android客户端与J2EE服务器的互联
  9. Android关于常用正则号码类Util
  10. 我们把 iOS 的 Cocoa Touch 移植到了 And