Android 自定義感光器控件SolarProgressView描馅,也可當(dāng)做普通ProgressBar使用

Android 自定義感光器控件SolarProgressView,也可當(dāng)做普通ProgressBar使用


本文出處: http://blog.csdn.net/qq_27512671/article/details/76020265
完整代碼獲让邸:https://github.com/miqt/SolarProgressView
實現(xiàn)效果:

實現(xiàn)效果
實現(xiàn)效果


實現(xiàn)思路:

①光線強度數(shù)據(jù)的獲劝蚶骸:Android光線傳感器
②光線強度的UI展示:自定義SolarProgressView
③光線數(shù)據(jù)源 --> UI展示需要數(shù)據(jù)的轉(zhuǎn)化: 數(shù)據(jù)梯度設(shè)置
④其他動畫效果的實現(xiàn):光線強度增加的過度動畫

光線強度數(shù)據(jù)的獲取:Android光線傳感器

Android光線傳感器是Android獲取周圍環(huán)境光的感光器元件誓竿,通過注冊感光器的傳感器監(jiān)聽,我們就可以通過傳感器傳過來的數(shù)值筷屡。

獲得光線傳感器實例:

manager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensor = manager.getDefaultSensor(Sensor.TYPE_LIGHT);

注冊監(jiān)聽器開始監(jiān)聽傳感器數(shù)據(jù)

 private SensorEventListener listener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {       
                        //取得數(shù)據(jù)
            Log.i("sensor_Data","\naccuracy : " + event.accuracy
            + "\ntimestamp : " + event.timestamp
            + "\nvalues : " + Arrays.toString(event.values));
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }
    };
@Override
protected void onResume() {
    super.onResume();
    manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}

在合適的時機取消注冊,節(jié)省資源占用:

@Override
protected void onPause() {
    super.onPause();
    manager.unregisterListener(listener);
}

光線強度的UI展示:自定義SolarProgressView

在用來展示的數(shù)據(jù)都準(zhǔn)備好了之后毙死,我們就要考慮如何將這些被整理好的數(shù)據(jù)展示出來了,實際上我們使用一個ProgressBar來展示即可规哲,但考慮到展示的美觀性和光線強弱變化的動畫交互诽表,我們決定自定義一個類似于太陽花的自定義控件來展示數(shù)據(jù)。并且這個自定義控件具有同ProgressBar類似的屬性竿奏,比如max(最大值)、progress(當(dāng)前值)等等泛啸。
有了明確的想法之后,開始開發(fā):

package com.mqt.solarprogressview;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.annotation.FloatRange;
import android.support.annotation.IntRange;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AnimationSet;
import android.view.animation.DecelerateInterpolator;


public class SolarView extends View {

    private int mColor = Color.RED;
    private int mMax = 9;
    private int mPregress = 0;

    private float mLolarScale;
    private int mLightRadius;
    private ObjectAnimator mScaleAnim;
    private int mLightRadiusAnim;
    private ObjectAnimator mColorAnim;

    public SolarView(Context context) {
        super(context);
        init(null, 0);
    }

    public SolarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public SolarView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {
        // Load attributes
        final TypedArray a = getContext().obtainStyledAttributes(
                attrs, R.styleable.SolarView, defStyle, 0);

        mColor = a.getColor(R.styleable.SolarView_color, Color.RED);
        mMax = a.getInt(R.styleable.SolarView_max, 9);
        mPregress = a.getInt(R.styleable.SolarView_pregress, 0);
        mLolarScale = a.getFloat(R.styleable.SolarView_solarScale, 0.25F);
        mLightRadius = a.getDimensionPixelSize(R.styleable.SolarView_lightRadius, 10);
        mLightRadiusAnim = mLightRadius;
        a.recycle();
        initPaint();
        initAnim();
    }

    private void initAnim() {
        mScaleAnim = ObjectAnimator
                .ofInt(this, "mLightRadiusAnim", mLightRadius / 2, mLightRadius, mLightRadius * 2, mLightRadius);
        mScaleAnim.setDuration(1200);//設(shè)置動畫時間
        mScaleAnim.setInterpolator(new DecelerateInterpolator());//設(shè)置動畫插入器吕粹,減速
        mScaleAnim.setRepeatCount(0);//設(shè)置動畫重復(fù)次數(shù),這里-1代表無限
        mScaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                mLightRadiusAnim = value;
                postInvalidate();
            }
        });

        mColorAnim = ObjectAnimator
                .ofArgb(this, "mColor", mColor, Color.rgb(250, 128, 10), mColor);
        mColorAnim.setDuration(1200);//設(shè)置動畫時間
        mColorAnim.setInterpolator(new DecelerateInterpolator());//設(shè)置動畫插入器匹耕,減速
        mColorAnim.setRepeatCount(0);//設(shè)置動畫重復(fù)次數(shù),這里-1代表無限
        mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                mColor = value;
                postInvalidate();
            }
        });
    }

    private int radumColor() {
        return Color.rgb((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
    }

    Paint mPaint;

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setColor(mColor);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //實心圓驶赏,直徑為控件的最小寬高的一半
        int min = Math.min(getWidth(), getHeight());
        float r = min * mLolarScale;
        mPaint.setColor(mColor);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, r, mPaint);
        for (int i = 0; i < mMax && i < mPregress; i++) {
            canvas.save();
            canvas.rotate((360f / mMax) * i, getWidth() >> 1, getHeight() >> 1);
            if (i == mPregress - 1) {
                canvas.drawCircle(getWidth() >> 1, getHeight() >> 3, mLightRadiusAnim, mPaint);
            } else {
                canvas.drawCircle(getWidth() >> 1, getHeight() >> 3, mLightRadius, mPaint);
            }
            canvas.restore();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
        int w = resolveSizeAndState(minw, widthMeasureSpec, 0);
        int minh = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
        int h = resolveSizeAndState(minh, heightMeasureSpec, 0);
        setMeasuredDimension(w, h);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    public int getColor() {
        return mColor;
    }

    public void setColor(@ColorInt int color) {
        this.mColor = color;
        postInvalidate();
    }

    public int getMax() {
        return mMax;
    }

    public void setMax(@IntRange(from = 0) int max) {
        this.mMax = max;
        postInvalidate();
    }

    public int getPregress() {
        return mPregress;
    }

    public void setPregress(@IntRange(from = 0) int pregress) {
        if (pregress > this.mPregress) {
            mColorAnim.cancel();
            mColorAnim.start();
            mScaleAnim.cancel();
            mScaleAnim.start();//啟動動畫
        }
        this.mPregress = pregress;

    }

    public float getLolarScale() {
        return mLolarScale;
    }

    public void setLolarScale(@FloatRange(from = 0, to = 1) float lolarScale) {
        this.mLolarScale = lolarScale;
        postInvalidate();
    }

    public int getLightRadius() {
        return mLightRadius;
    }

    public void setLightRadius(@IntRange(from = 0) int lightRadius) {
        this.mLightRadius = lightRadius;
        postInvalidate();
    }
}

自定義屬性XML:

<resources>
    <declare-styleable name="SolarView">
        <attr name="max" format="integer" />
        <attr name="pregress" format="integer" />
        <attr name="color" format="color" />
        <attr name="solarScale" format="float" />
        <attr name="lightRadius" format="dimension" />
    </declare-styleable>
</resources>

光線數(shù)據(jù)源 --> UI展示需要數(shù)據(jù)的轉(zhuǎn)化: 數(shù)據(jù)梯度設(shè)置

在我們獲取到傳感器給出的光照強度數(shù)據(jù)源后煤傍,我們無法直接使用,因為光線給出的數(shù)據(jù)與UI展示需要的數(shù)據(jù)不同嘱蛋,因此我們需要下轉(zhuǎn)化,直接在傳感器監(jiān)聽中添加代碼即可:

private SensorEventListener listener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            float intensity = event.values[2];
            int size = (int) ((intensity * sv_light.getMax() / 120));
            sv_light.setPregress(size);
            textView.setText(
                    "\naccuracy : " + event.accuracy
                            + "\ntimestamp : " + event.timestamp
                            + "\nvalues : " + Arrays.toString(event.values)
            );
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }
    };

其他動畫效果的實現(xiàn):光線強度增加的過度動畫

光線傳感器數(shù)據(jù)獲取完成了蒋失,用于UI展示的自定義控件也寫好了,數(shù)據(jù)也匹配好了可以正常展示了桐玻,但我們可能還不會滿足,我們可能還希望給這個自定義控件在傳感器數(shù)據(jù)發(fā)生變化的時候镊靴,有一個動畫出來。這個動畫其實在上面粘貼的代碼中已經(jīng)有了偏竟,這里只是介紹一下給這個自定義view添加動畫的思路:
我們知道自定義view的所有的視圖都是在onDraw(Canvas canvas)方法中用Canvas畫出來的,而化成什么樣子又是其中的各種參數(shù)控制的踊谋,例如我們在自定義控件中畫一個圓,我們只需要動態(tài)的改變這個圓的半徑殖蚕,就能達到這個圓的放大縮小的目的,當(dāng)我們有規(guī)律的并且足夠頻繁改變這個值睦疫,就可以達到平滑的動態(tài)效果了害驹。例如實現(xiàn)控件中控件隨progress的變化顏色漸變:

  mColorAnim = ObjectAnimator
                .ofArgb(this, "mColor", mColor, Color.rgb(250, 128, 10), mColor);
        mColorAnim.setDuration(1200);//設(shè)置動畫時間
        mColorAnim.setInterpolator(new DecelerateInterpolator());//設(shè)置動畫插入器宛官,減速
        mColorAnim.setRepeatCount(0);//設(shè)置動畫重復(fù)次數(shù)葫松,這里-1代表無限
        mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                mColor = value;
                postInvalidate();//重新繪制控件
            }
        });

這樣底洗,我們的自定義感光器控件的“感光”、“數(shù)據(jù)展示”和一切其他的動畫效果亥揖,就達成了,干杯P炜椤!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胡控,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子昼激,更是在濱河造成了極大的恐慌,老刑警劉巖橙困,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異凡傅,居然都是意外死亡辟狈,警方通過查閱死者的電腦和手機夏跷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壹蔓,“玉大人,你說我怎么就攤上這事猫态。” “怎么了亲雪?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匆光。 經(jīng)常有香客問我,道長终息,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任周崭,我火速辦了婚禮,結(jié)果婚禮上续镇,老公的妹妹穿的比我還像新娘美澳。我一直安慰自己摸航,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布酱虎。 她就那樣靜靜地躺著,像睡著了一般读串。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恢暖,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音杰捂,去河邊找鬼。 笑死嫁佳,一個胖子當(dāng)著我的面吹牛峭弟,可吹牛的內(nèi)容都是我干的脱拼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼熄浓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赌蔑?” 一聲冷哼從身側(cè)響起俯在,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤跷乐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后趾浅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體馒稍,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡浅侨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了如输。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鼓黔。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡澳化,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出稳吮,到底是詐尸還是另有隱情,我是刑警寧澤盖高,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站喻奥,受9級特大地震影響席纽,放射性物質(zhì)發(fā)生泄漏撞蚕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一甥厦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧刀疙,春花似錦舶赔、人聲如沸谦秧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至集歇,卻和暖如春桶略,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惶翻。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蹬挺,地道東北人它掂。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像虐秋,于是被迫代替她去往敵國和親榕茧。 傳聞我的和親對象是個殘疾皇子客给,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,074評論 25 707
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,755評論 22 665
  • 天冷了在客廳都呆不住了,和兒子泡完腳以后我就上床了蜻拨,兒子也回房間了,趴在被窩里看書桩引,一個多小時了,還在看坑匠,好像上癮...
    李宇航媽媽閱讀 110評論 0 0
  • 所謂父母一場,就是一次次的送別厘灼。他們用背影告訴你夹纫,不必追
    柳樹下的孩子閱讀 126評論 0 1
  • 今年我十八舰讹,上大一,在外地上學(xué)闪朱≡孪唬可能很多中國學(xué)生會和我一樣不去想打工的事情监透,因為父母會說:賺錢不是你該做的事情,你...
    甛FLAMINGO閱讀 1,533評論 0 2