畫個(gè)知乎的弧~仿知乎日?qǐng)?bào)開屏頁

先看看知乎日?qǐng)?bào)開屏頁的效果,非常漂亮的開屏效果

ezgif.com-resize (2).gif

然后我來一個(gè)

ezgif.com-resize (1).gif

也不錯(cuò)感覺可以以假亂真了

很簡單,直接開始宪睹。
實(shí)現(xiàn)這個(gè)效果先制定個(gè)三步走策略

  1. 底部布局上滑展示扫腺。
  2. 畫一個(gè)知弧岗照。
  3. 顯示圖片
底部布局上滑展示

直接上代碼吧,屬性動(dòng)畫基本使用

private void startAnimation() {
        //位移動(dòng)畫笆环,從底部滑出攒至,Y方向移動(dòng),mHeight是底部布局的高度
        ObjectAnimator translationAnimator= ObjectAnimator.ofFloat(rv_bottom, "translationY", mHeight, 0f);
        //設(shè)置時(shí)長
        translationAnimator.setDuration(1000);
        //透明度漸變動(dòng)畫
        ObjectAnimator alphaAnimatorator = ObjectAnimator.ofFloat(rv_bottom, "alpha", 0f,1f);
        //設(shè)置時(shí)長
        alphaAnimatorator.setDuration(2500);
        //添加監(jiān)聽器,位移結(jié)束后躁劣,畫圓弧開始
        translationAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                zhview.startAnimation();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        AnimatorSet set = new AnimatorSet();
        //兩個(gè)動(dòng)畫一起執(zhí)行
        set.play(translationAnimator).with(alphaAnimatorator);
        //go
        set.start();
    }

在位移動(dòng)畫結(jié)束的時(shí)候迫吐,調(diào)用了自定義的view的方法,開始了畫弧的操作账忘。

畫個(gè)知弧

接下來開始畫畫~ 自定義一個(gè)view志膀,重寫ondraw方法熙宇,開畫之前先初始化一個(gè)合適的畫筆。

 private void initPaint() {
        mPaint1 = new Paint();
       //設(shè)置畫筆顏色
        mPaint1.setColor(Color.WHITE);
        // 設(shè)置畫筆的樣式為圓形
        mPaint1.setStrokeCap(Paint.Cap.ROUND);
        // 設(shè)置畫筆的填充樣式為描邊
        mPaint1.setStyle(Paint.Style.STROKE);
        //抗鋸齒
        mPaint1.setAntiAlias(true);
        //設(shè)置畫筆寬度
        mPaint1.setStrokeWidth(mBorderWidth1);

        mPaint2 = new Paint();
        mPaint2.setColor(Color.WHITE);
        mPaint2.setStyle(Paint.Style.STROKE);
        mPaint2.setAntiAlias(true);
        mPaint2.setStrokeWidth(mBorderWidth2);
    }

mPaint1用來畫弧梧却,設(shè)置填充樣式為描邊奇颠,這樣起碼我們就能輕松畫一個(gè)圓環(huán)了。其實(shí)要畫的知弧就是一個(gè)圓環(huán)被啃去了一塊的感覺~ 但被啃的地方很光滑放航,所以需要一個(gè)圓頭的畫筆 烈拒。
mPaint2用來畫外面的圓角矩形環(huán),設(shè)置也差不多广鳍。

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLACK);
        //矩形輪廓荆几,圓弧在內(nèi)部,給予一定的內(nèi)邊距
        RectF rectF1 = new RectF(mBorderWidth1/2+dipToPx(8), mBorderWidth1/2+dipToPx(8), getWidth() -mBorderWidth1/2-dipToPx(8),getWidth()-mBorderWidth1/2-dipToPx(8) );
        //畫圓弧 參數(shù)1:矩形輪廓 參數(shù)2:起始位置 參數(shù)3:掃過的范圍赊时,初始為0 參數(shù)4:是否連接圓心
        canvas.drawArc(rectF1, 90, mCurrentRadian, false, mPaint1);
        //矩形輪廓
        RectF rectF2 = new RectF(mBorderWidth2/2,mBorderWidth2/2,getWidth()-mBorderWidth2/2,getWidth()-mBorderWidth2/2);
        //畫圓角矩形邊框 參數(shù)2 3設(shè)置x,y方向的圓角corner 都要設(shè)置
        canvas.drawRoundRect(rectF2,dipToPx(8),dipToPx(8),mPaint2);

    }

代碼量很少吨铸,但要明確環(huán)的畫法,不論是畫圓環(huán)還是圓角矩形環(huán)祖秒,需要先確定一個(gè)基準(zhǔn)矩形诞吱。基準(zhǔn)矩形的位置和大小確定環(huán)的位置和大小竭缝。畫弧的方法canvas.drawArc中的參數(shù)2 3設(shè)置了開始畫弧的位置和畫弧的范圍房维。看一下運(yùn)行效果抬纸,圓弧的起始畫點(diǎn)在圓心的正下方咙俩,X軸正方向?yàn)?度,所以起始畫點(diǎn)為90度湿故。

接下來就使用不斷增大畫弧的范圍的方式來完成動(dòng)畫的實(shí)現(xiàn)阿趁。上代碼

private void startAnimationDraw() {
        //圓弧掃過范圍為270度
        ValueAnimator valueAnimator=new ValueAnimator().ofFloat(0,270);
        //動(dòng)畫持續(xù)時(shí)間
        valueAnimator.setDuration(mDuration);
        //設(shè)置插值器,中間快兩頭慢
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        //添加狀態(tài)監(jiān)聽器
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //不斷增大圓弧掃過的范圍坛猪,并重繪來實(shí)現(xiàn)動(dòng)畫效果
                mCurrentRadian= (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.start();
    }

使用ValueAnimator.ofFloat創(chuàng)建一個(gè)值為0-270的動(dòng)畫脖阵,添加狀態(tài)監(jiān)聽,在動(dòng)畫執(zhí)行的過程中不斷增大掃過的范圍并重繪視圖從而實(shí)現(xiàn)了畫弧的動(dòng)畫效果墅茉。

整個(gè)過程就是canvas配合屬性動(dòng)畫的方式完成了動(dòng)態(tài)繪圖独撇,一點(diǎn)也不復(fù)雜。

顯示圖片

這里我使用的是Glide加載的本地圖片躁锁,設(shè)置了延遲加載把握?qǐng)D片加載時(shí)機(jī),獲得更好的開屏效果

 //延時(shí)加載圖片
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Glide.with(MainActivity.this).
                                load(R.drawable.timg).
                                centerCrop().
                                skipMemoryCache(true).
                                diskCacheStrategy(DiskCacheStrategy.NONE).
                                crossFade(500).
                                into(image)
                        ;
                    }
                },2000);

這里個(gè)人認(rèn)為知乎也是用某種方式預(yù)先把圖片下載到本地完成來把握精確地加載時(shí)機(jī)卵史,不知道是不是這樣战转。。

最后貼一下代碼

activity

public class MainActivity extends AppCompatActivity {
    private RelativeLayout rv_bottom;
    private Zhview zhview;
    private float mHeight;
    private ImageView image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        rv_bottom= (RelativeLayout) this.findViewById(R.id.rv_bottom);
        zhview= (Zhview) this.findViewById(R.id.zhview);
        image= (ImageView) this.findViewById(R.id.image);
        rv_bottom.post(new Runnable() {
            @Override
            public void run() {
                //獲得底部的高度
                mHeight=rv_bottom.getHeight();
                //開始動(dòng)畫
                startAnimation();
                //延時(shí)加載圖片
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Glide.with(MainActivity.this).
                                load(R.drawable.timg).
                                centerCrop().
                                skipMemoryCache(true).
                                diskCacheStrategy(DiskCacheStrategy.NONE).
                                crossFade(500).
                                into(image)
                        ;
                    }
                },2000);
            }
        });
    }

    private void startAnimation() {
        //位移動(dòng)畫以躯,從底部滑出槐秧,Y方向移動(dòng)
        ObjectAnimator translationAnimator= ObjectAnimator.ofFloat(rv_bottom, "translationY", mHeight, 0f);
        //設(shè)置時(shí)長
        translationAnimator.setDuration(1000);
        //透明度漸變動(dòng)畫
        ObjectAnimator alphaAnimatorator = ObjectAnimator.ofFloat(rv_bottom, "alpha", 0f,1f);
        //設(shè)置時(shí)長
        alphaAnimatorator.setDuration(2500);
        //添加監(jiān)聽器啄踊,位移結(jié)束后,畫圓弧開始
        translationAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                zhview.startAnimation();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        AnimatorSet set = new AnimatorSet();
        //兩個(gè)動(dòng)畫一起執(zhí)行
        set.play(translationAnimator).with(alphaAnimatorator);
        //go
        set.start();
    }
}

自定義view

public class Zhview extends View {
    private Paint mPaint1;  //圓弧畫筆
    private Paint mPaint2;  //外框畫筆
    //圓弧寬度
    private int mBorderWidth1=dipToPx(5);
    //外框?qū)挾?    private int mBorderWidth2=dipToPx(1.5f);
    //掃過的范圍
    private float mCurrentRadian=0;
    //動(dòng)畫持續(xù)時(shí)長
    private int mDuration=1500;

    public Zhview(Context context) {
        this(context,null);
    }

    public Zhview(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);

    }

    public Zhview(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化畫筆
        initPaint();
    }

    private void initPaint() {
        mPaint1 = new Paint();
       //設(shè)置畫筆顏色
        mPaint1.setColor(Color.WHITE);
        // 設(shè)置畫筆的樣式為圓形
        mPaint1.setStrokeCap(Paint.Cap.ROUND);
        // 設(shè)置畫筆的填充樣式為描邊
        mPaint1.setStyle(Paint.Style.STROKE);
        //抗鋸齒
        mPaint1.setAntiAlias(true);
        //設(shè)置畫筆寬度
        mPaint1.setStrokeWidth(mBorderWidth1);

        mPaint2 = new Paint();
        mPaint2.setColor(Color.WHITE);
        mPaint2.setStyle(Paint.Style.STROKE);
        mPaint2.setAntiAlias(true);
        mPaint2.setStrokeWidth(mBorderWidth2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLACK);
        //矩形輪廓刁标,圓弧在內(nèi)部颠通,給予一定的內(nèi)邊距
        RectF rectF1 = new RectF(mBorderWidth1/2+dipToPx(8), mBorderWidth1/2+dipToPx(8), getWidth() -mBorderWidth1/2-dipToPx(8),getWidth()-mBorderWidth1/2-dipToPx(8) );
        //畫圓弧 參數(shù)1:矩形輪廓 參數(shù)2:起始位置 參數(shù)3:掃過的范圍,初始為0 參數(shù)4:是否連接圓心
        canvas.drawArc(rectF1, 90, mCurrentRadian, false, mPaint1);
        //矩形輪廓
        RectF rectF2 = new RectF(mBorderWidth2/2,mBorderWidth2/2,getWidth()-mBorderWidth2/2,getWidth()-mBorderWidth2/2);
        //畫圓角矩形邊框 參數(shù)2 3設(shè)置x,y方向的圓角corner 都要設(shè)置
        canvas.drawRoundRect(rectF2,dipToPx(8),dipToPx(8),mPaint2);

    }

    private void startAnimationDraw() {
        //圓弧掃過范圍為270度
        ValueAnimator valueAnimator=new ValueAnimator().ofFloat(0,270);
        //動(dòng)畫持續(xù)時(shí)間
        valueAnimator.setDuration(mDuration);
        //設(shè)置插值器膀懈,中間快兩頭慢
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        //添加狀態(tài)監(jiān)聽器
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //不斷增大圓弧掃過的范圍顿锰,并重繪來實(shí)現(xiàn)動(dòng)畫效果
                mCurrentRadian= (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.start();
    }
    //開始動(dòng)畫
    public void startAnimation(){
        startAnimationDraw();
    }
    private int dipToPx(float dip) {
        float density = getContext().getResources().getDisplayMetrics().density;
        return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));
    }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    tools:context="com.zhview.MainActivity">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/rv_bottom" />

    <RelativeLayout
        android:id="@+id/rv_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:padding="20dp">

        <com.zhview.Zhview
            android:id="@+id/zhview"
            android:layout_width="46dp"
            android:layout_height="46dp"
            android:layout_marginLeft="10dp" />

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_toRightOf="@+id/zhview"
            android:text="知乎日?qǐng)?bào)"
            android:textColor="@android:color/white"
            android:textSize="19sp"

            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@+id/zhview"
            android:layout_marginLeft="20dp"
            android:layout_toRightOf="@+id/zhview"
            android:text="每天三次,每次七分鐘"
            android:textColor="@android:color/darker_gray"
            android:textSize="13sp" />
    </RelativeLayout>
</RelativeLayout>

我個(gè)人挺喜歡這些實(shí)現(xiàn)起來不復(fù)雜但體驗(yàn)非常好的設(shè)計(jì)启搂,見到了就努力實(shí)現(xiàn)一下硼控,然后邊學(xué)邊分享,要是跟我一樣感興趣的話可以關(guān)注我一下哦~
完整代碼地址https://github.com/yanyiqun001/zhview

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胳赌,一起剝皮案震驚了整個(gè)濱河市牢撼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疑苫,老刑警劉巖熏版,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捍掺,居然都是意外死亡撼短,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門乡小,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阔加,“玉大人,你說我怎么就攤上這事满钟∈だ疲” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵湃番,是天一觀的道長夭织。 經(jīng)常有香客問我,道長吠撮,這世上最難降的妖魔是什么尊惰? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮泥兰,結(jié)果婚禮上弄屡,老公的妹妹穿的比我還像新娘。我一直安慰自己鞋诗,他們只是感情好膀捷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著削彬,像睡著了一般全庸。 火紅的嫁衣襯著肌膚如雪秀仲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天壶笼,我揣著相機(jī)與錄音神僵,去河邊找鬼。 笑死覆劈,一個(gè)胖子當(dāng)著我的面吹牛保礼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播墩崩,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼氓英,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了鹦筹?” 一聲冷哼從身側(cè)響起铝阐,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铐拐,沒想到半個(gè)月后徘键,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遍蟋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年吹害,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虚青。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡它呀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棒厘,到底是詐尸還是另有隱情纵穿,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布奢人,位于F島的核電站谓媒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏何乎。R本人自食惡果不足惜句惯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望支救。 院中可真熱鬧抢野,春花似錦、人聲如沸各墨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欲主。三九已至邓厕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扁瓢,已是汗流浹背详恼。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留引几,地道東北人昧互。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像伟桅,于是被迫代替她去往敵國和親敞掘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,180評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫楣铁、插件玖雁、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,107評(píng)論 4 62
  • 一 他還記得第一次看到她時(shí)的那種悸動(dòng),坐在她45度后方盖腕,無聊中向前一瞥赫冬,本已游開的目光頓時(shí)被某種力量拉了回來。中長...
    whaowhao閱讀 195評(píng)論 0 2
  • 1.安裝并破解Chales下載應(yīng)用:點(diǎn)擊下載charles 3.11.5破解版安裝應(yīng)用:以上安裝文件是mac版溃列,w...
    Jerry_unused閱讀 1,153評(píng)論 0 0
  • 荇菜搖搖憐枯塘 葡萄滴水對(duì)軒窗 發(fā)際微涼知秋長 迎風(fēng)清側(cè)補(bǔ)秋霜 蓑衣掃竹掛瓦房 鞋履和泥裹滿香 夕陽晚照烏衣巷 桂...
    梅涼閱讀 509評(píng)論 0 4