完全自定義控件-仿探探搜索附近人動(dòng)畫

老夫?yàn)榱私裉焓巧焚M(fèi)苦心啊,哈哈哈哈
一直想模仿探探的一個(gè)雷達(dá)搜索效果(探探應(yīng)該用過吧,就是和陌陌類似的不可描述app)
總結(jié)了前面兩篇博客,今天終于可以上手干了血崭!

完全自定義控件-自定義雷達(dá)掃描控件
完全自定義控件-自定義絢麗水波紋效果

仿探探雷達(dá)搜索附近人動(dòng)畫

效果展示

效果展示

需求分析


外圈自動(dòng)旋轉(zhuǎn)(類似雷達(dá),通過旋轉(zhuǎn)背景圖片實(shí)現(xiàn))厘灼。點(diǎn)擊中間Logo圖片會(huì)對(duì)圖片會(huì)進(jìn)行縮放夹纫,并產(chǎn)生"波紋"效果。

實(shí)現(xiàn)思路


  1. 自定義類繼承View手幢,初始化數(shù)據(jù)
  2. 定義每個(gè)圓環(huán)的實(shí)體類 Wave捷凄,并初始化繪制圓環(huán)的畫筆的數(shù)據(jù)。
  3. 重寫onTouchEvent方法围来,down時(shí),獲得坐標(biāo)點(diǎn),做為圓環(huán)圓心监透。
  4. 重寫onDraw()方法桶错,繪制雷達(dá)掃描,繪制波紋胀蛮,繪制中心圖片縮放動(dòng)畫院刁。
  5. 利用Handler實(shí)現(xiàn)循環(huán)

1. 自定義類繼承View,初始化數(shù)據(jù)


public class TantanRadarView extends View {
    private int w, h;     //獲取控件寬高粪狼,用于畫圓的坐標(biāo)位置以及半徑
    private Bitmap mBitmap;      //兩張圖片
    private Bitmap mRadarBitmap;
    private float[] s = {1.05f, 1.1f, 1.15f, 1.2f, 1.25f, 1.2f, 1.1f, 1.0f, 0.9f, 0.8f, 0.75f, 0.8f, 0.9f, 1.0f};     //縮放比例的數(shù)組
    private int mScaleIndex = 0;      //圖片縮放的下標(biāo)
    private int mRadarBitmapWidth;     //圖片寬高
    private int mRadarBitmapHeight;
    private int mBitmapWidth;
    private int mBitmapHeight;
    private float x; //觸摸點(diǎn)的坐標(biāo)
    private float y;
    private Boolean isTouch;     //圖片是否被觸摸
    private ArrayList<Wave> mList;     //存放圓環(huán)的集合
    private Matrix mMatrix;
    private int start = 0;     //開始的角度
 
    private Handler mHandler = new Handler();
 
    public TantanRadarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();    //初始化數(shù)據(jù)
        mList = new ArrayList<Wave>();
        mHandler.post(run);          //提交計(jì)劃任務(wù)馬上執(zhí)行
    }

    private void init() {
        //加載圖片退腥,得到圖片的寬和高
        mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.logo);
        mBitmapWidth = mBitmap.getWidth();
        mBitmapHeight = mBitmap.getHeight();
        mRadarBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.radar);
        mRadarBitmapWidth = mRadarBitmap.getWidth();
        mRadarBitmapHeight = mRadarBitmap.getHeight();
        mMatrix = new Matrix();          //初始化矩陣
        isTouch = false;
    }

2. 定義實(shí)體類 Wave


public class Wave {
    public float x;//圓心x坐標(biāo)
    public float y;//圓心y坐標(biāo)
    public Paint paint; //畫圓的畫筆
    public float width; //線條寬度
    public int radius; //圓的半徑
 
    public Wave(float x, float y) {
        this.x = x;
        this.y = y;
        initData();
    }
    /**
     * 初始化數(shù)據(jù),每次點(diǎn)擊一次都要初始化一次
     */
    private void initData() {
        paint=new Paint();//因?yàn)辄c(diǎn)擊一次需要畫出不同的圓環(huán)
        paint.setAntiAlias(true);//打開抗鋸齒
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);//描邊
        paint.setStrokeWidth(width);//設(shè)置描邊寬度
        paint.setAlpha(255);//透明度的設(shè)置(0-255),0為完全透明
        radius=50;//控制波紋的半徑為圖片半徑
        width=7;
    }
}

3. 重寫onTouchEvent方法


public boolean onTouchEvent(MotionEvent event) {
 
        x = event.getX();
        y = event.getY();
 
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                //在圖片的范圍內(nèi)點(diǎn)擊
                if (x > w / 2 - mBitmapWidth / 2 && x < w / 2 + mBitmapWidth / 2
                        && y > h / 2 - mBitmapHeight / 2 && y < h / 2 + mBitmapHeight / 2) {
                    //波紋的圓心固定
                    x = w / 2;
                    y = h / 2;
                    deleteItem();
                    Wave wave = new Wave(x, y);
                    mList.add(wave);
                    isTouch = true;
                    //縮放數(shù)組從0下標(biāo)開始縮放
                    mScaleIndex=0;
                }
                break;
        }
        return true;
    }
   //從集合中刪除不可見的波紋

   private void deleteItem() {
        for (int i = 0; i < mList.size(); i++) {
            if (mList.get(i).paint.getAlpha() == 0) {
                mList.remove(i);
            }
        }
    }

4. 開始繪制


protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        w = getMeasuredWidth();//獲取view的寬度
        h = getMeasuredHeight();//獲取view的高度
 
        //開始掃描
        startRadar(canvas);
        startWave(canvas);
 
        //如果圖片被點(diǎn)擊則進(jìn)行縮放動(dòng)畫
        if (isTouch) {
            touchBitmapEvent(canvas);
        } else {
            canvas.drawBitmap(mBitmap, w / 2 - mBitmapWidth / 2, h / 2 - mBitmapHeight / 2, null);
        }
    }

繪制波紋

  • 波紋寬度隨半徑擴(kuò)大減小
private void startWave(Canvas canvas) {
        //避免程序一運(yùn)行就進(jìn)行繪制
        if (mList.size() > 0) {
 
            //對(duì)集合中的圓環(huán)對(duì)象循環(huán)繪制
            for (Wave wave : mList) {
                canvas.drawCircle(wave.x, wave.y, wave.radius, wave.paint);
                wave.radius += 3;
                //對(duì)畫筆透明度進(jìn)行操作
                int alpha = wave.paint.getAlpha();
                if (alpha < 160) {
                    alpha = 0;
                } else {
                    alpha -= 2;
                }
                //設(shè)置畫筆寬度和透明度
                wave.paint.setStrokeWidth(wave.width-wave.radius / 30);
                wave.paint.setAlpha(alpha);
 
            }
        }
    }

繪制雷達(dá)掃描

  • 通過矩形對(duì)背景圖片進(jìn)行控制,旋轉(zhuǎn)角度在Handler中自增再榄,通過反復(fù)調(diào)用onDraw()方法實(shí)現(xiàn)動(dòng)畫
  • Matrix的set狡刘,pre,post方法調(diào)用順序

Matrix調(diào)用一系列set,pre,post方法時(shí),可視為將這些方法插入到一個(gè)隊(duì)列困鸥。按照隊(duì)列中從頭至尾的順序調(diào)用執(zhí)行嗅蔬。
pre表示在隊(duì)頭插入一個(gè)方法
post表示在隊(duì)尾插入一個(gè)方法
set表示把當(dāng)前隊(duì)列清空,并且總是位于隊(duì)列的最中間位置
當(dāng)執(zhí)行了一次set后:pre方法總是插入到set前部的隊(duì)列的最前面,post方法總是插入到set后部的隊(duì)列的最后面

詳細(xì)解析Matrix的set,pre,post調(diào)用順序

private void startRadar(Canvas canvas) {
 
        //矩陣執(zhí)行隊(duì)列創(chuàng)建
        mMatrix.setRotate(start, mRadarBitmap.getWidth() / 2, mRadarBitmap.getHeight() / 2);
        mMatrix.postScale(1.3f, 1.3f);
        mMatrix.postTranslate(w / 2 - mRadarBitmapWidth / 2 * 1.3f, h / 2 - mRadarBitmapHeight / 2 * 1.3f);
 
        //對(duì)圖片進(jìn)行操作
        canvas.drawBitmap(mRadarBitmap, mMatrix, null);
    }

繪制圖片縮放動(dòng)畫

private void touchBitmapEvent(Canvas canvas) {
        if (isTouch) {
 
            if (mScaleIndex < s.length) {
                //循環(huán)讀取數(shù)組的值疾就,對(duì)圖片進(jìn)行縮放
                Matrix matrix = new Matrix();
                matrix.setScale(s[mScaleIndex], s[mScaleIndex], mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);
                matrix.postTranslate(getWidth() / 2 - mBitmap.getWidth() / 2, getHeight() / 2 - mBitmap.getHeight() / 2);
                canvas.drawBitmap(mBitmap, matrix, null);
                mScaleIndex++;
            } else {
                canvas.drawBitmap(mBitmap, getWidth() / 2 - mBitmapWidth / 2, getHeight() / 2 - mBitmapHeight / 2, null);
                isTouch = false;
            }
        }
    }

5. 通過Handler循環(huán)繪制實(shí)現(xiàn)轉(zhuǎn)動(dòng)


  • 這可是實(shí)現(xiàn)交互和動(dòng)畫的靈魂澜术!
private Handler mHandler = new Handler();
 
    Runnable run = new Runnable() {
 
        @Override
        public void run() {
            start+=5;
            //刷新UI
            postInvalidate();
            //如果到了360度,則重新開始
            start = start == 360 ? 0 : start;
            //延遲執(zhí)行猬腰,可以通過延遲重繪的時(shí)間來控制動(dòng)畫的快慢
            postDelayed(this, 50);
        }
    };

這里是項(xiàng)目地址鸟废。

參考文章
http://www.reibang.com/p/88cc7255ab12#

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市姑荷,隨后出現(xiàn)的幾起案子侮攀,更是在濱河造成了極大的恐慌,老刑警劉巖厢拭,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兰英,死亡現(xiàn)場離奇詭異,居然都是意外死亡供鸠,警方通過查閱死者的電腦和手機(jī)畦贸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來楞捂,“玉大人薄坏,你說我怎么就攤上這事≌郑” “怎么了胶坠?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長繁堡。 經(jīng)常有香客問我沈善,道長乡数,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任闻牡,我火速辦了婚禮净赴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘罩润。我一直安慰自己玖翅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布割以。 她就那樣靜靜地躺著金度,像睡著了一般。 火紅的嫁衣襯著肌膚如雪严沥。 梳的紋絲不亂的頭發(fā)上猜极,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音祝峻,去河邊找鬼魔吐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛莱找,可吹牛的內(nèi)容都是我干的酬姆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼奥溺,長吁一口氣:“原來是場噩夢啊……” “哼辞色!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起浮定,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤相满,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后桦卒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體立美,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年方灾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了建蹄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡裕偿,死狀恐怖洞慎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘿棘,我是刑警寧澤劲腿,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站鸟妙,受9級(jí)特大地震影響焦人,放射性物質(zhì)發(fā)生泄漏挥吵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一垃瞧、第九天 我趴在偏房一處隱蔽的房頂上張望蔫劣。 院中可真熱鬧坪郭,春花似錦个从、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沪曙,卻和暖如春奕污,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背液走。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工碳默, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缘眶。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓嘱根,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巷懈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子该抒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,732評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)顶燕,斷路器凑保,智...
    卡卡羅2017閱讀 134,626評(píng)論 18 139
  • 通過之前的詳細(xì)分析,我們知道:在measure中測量了View的大小涌攻,在layout階段確定了View的位置欧引。 完...
    SnowDragonYY閱讀 936評(píng)論 0 3
  • 最近班上的熊孩子們表現(xiàn)挺好的,我少生了很多氣恳谎。課堂表現(xiàn)更好了芝此,作業(yè)完成也更積極了,更難得的是有幾個(gè)老大難的孩子惠爽,也...
    薛薛閑扯閱讀 747評(píng)論 0 0
  • 關(guān)于附隨義務(wù)能否擴(kuò)大到侵權(quán)的領(lǐng)域癌蓖,是值得研 究的。試舉一案予以說明: 某日中午婚肆,原 告乘坐被告某客運(yùn)公司的專線公共...
    王信澤閱讀 155評(píng)論 0 0