欠大家一篇文章,這段時間事情較多常在外面跑來跑去的,其本上沒什么時間靜下來寫代碼。然后看到了不少的網(wǎng)友給我反饋有送,想看一下是如何實現(xiàn)這個效果的:
原面試題傳送門。
我看到有人通過RecyclerView來實現(xiàn)這個效果僧家,其實也可以雀摘,只是背離了考查自定義UI開發(fā)的目的。這里我做了一個簡單的實現(xiàn)八拱,當(dāng)然是不完整的阵赠,我希望大家自己動手來完善它,那樣這個實例中涉及的知識才能真正轉(zhuǎn)化成你自己的技能肌稻。
這里簡單說一下實現(xiàn)步驟:
- 實現(xiàn)自定義的圓角帶陰影的View
- 實現(xiàn)GroupView+Adapter完成布局
- 實現(xiàn)滑動
源碼下載地址:Github
實現(xiàn)圓角帶陰影的ImaegView
之前我們也有提過有幾種實現(xiàn)圖片圓角的方式豌注,這里我們只展示一下使用BitmapShader的方式。我們使用paint.setShader設(shè)置畫筆的內(nèi)容灯萍,再用drawCircle通過設(shè)定好的paint畫圓即可實現(xiàn)圖片的圓角效果轧铁。在真正償試時,你可能需要先解決如下的問題:
- canvas的坐標(biāo)系和drawCircle的坐標(biāo)關(guān)系旦棉。
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
- 了解Shader和BitmapShader齿风。
new BitmapShader(imageBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
BitmapShader的三種TileMode: CLAMP, REPEAT, MIRROR
了解一些Matrix的基礎(chǔ)知識。
學(xué)會讓Matrix進(jìn)行縮放讓圖片居中顯示绑洛。了解關(guān)于Paint的一些用法救斑。
學(xué)會給paint添加陰影效果:
public void setShadowLayer(float radius, float dx, float dy, int shadowColor)
這里不需要像面試一樣問你Canvas、Drawable和Bitmap之間的關(guān)系真屯,因為當(dāng)你動手實現(xiàn)完這這個實例時脸候,你自然會明白他們之間的關(guān)聯(lián)。
具體實現(xiàn)參考:CircularImageView.java
實現(xiàn)GroupView+Adapter完成布局
onLayout在ViewGroup中是一個抽象方法,所以你自定義ViewGroup的話首先要重寫它的一個實現(xiàn)运沦。
我們需要給每一個可顯示的子View設(shè)置它的顯示位置(確定它四個點的位置):
public void layout(int l, int t, int r, int b)
在這個onLayout中我們先用最簡單的線性布局一行排開所有的子View:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int viewGroupWidth = getMeasuredWidth();
int painterPosX = l;
int painterPosY = t;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
int width = childView.getMeasuredWidth();
int height = childView.getMeasuredHeight();
childView.layout(painterPosX, painterPosY, painterPosX + width, painterPosY + height);
painterPosX += width;
}
}
驗證onLayout如保布局泵额,我們第一步是給ViewGroup添加子View,這里我們先用一種最簡單的方式携添,在xml文件中直接添加:
<net.goeasyway.coverflow.CoverflowView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<net.goeasyway.coverflow.CircularImageView
android:layout_width="96dp"
android:layout_height="96dp"
android:src="@mipmap/goeasyway"/>
<net.goeasyway.coverflow.CircularImageView
android:layout_width="96dp"
android:layout_height="96dp"
android:src="@mipmap/goeasyway"/>
<net.goeasyway.coverflow.CircularImageView
android:layout_width="96dp"
android:layout_height="96dp"
android:src="@mipmap/goeasyway"/>
<net.goeasyway.coverflow.CircularImageView
android:layout_width="96dp"
android:layout_height="96dp"
android:src="@mipmap/goeasyway"/>
<net.goeasyway.coverflow.CircularImageView
android:layout_width="96dp"
android:layout_height="96dp"
android:src="@mipmap/goeasyway"/>
</net.goeasyway.coverflow.CoverflowView>
我們在CoverflowView下添加了5個CircularImageView的子View嫁盲,在屏幕上看只能顯示下4個:
當(dāng)然,現(xiàn)在我們希望通過滑動能看到第5個子View烈掠。
實現(xiàn)滑動
其實滑動和動畫效果的原理是一樣的羞秤,就是讓子View在短時間內(nèi)連續(xù)地改變坐位或者大小(當(dāng)然還有顏色等其他因素左敌,也會產(chǎn)生動態(tài)的效果)瘾蛋。一秒內(nèi)能顯示的連續(xù)改變越多效果也就是越流暢(有點象錄音的采樣率)。
所以矫限,在動手前你還需要檢查一下下面羅列的概念或方法你是否有不明白的哺哼,可以在動手前稍稍了解一下:
獲得滑動輸入:onInterceptTouchEvent、onTouchEvent
計算:computeScroll奇唤、scrollBy & scrollTo幸斥、Scroller
調(diào)用View的繪制流程更新View:onMeasure匹摇、onLayout咬扇、onDraw
之后的問題會集中在怎么確定選中的Item,所以你會比較清楚一些常用到的坐標(biāo)值各表示什么意思廊勃,如getX(), getRawX(), getScrollX()懈贺。
最后按這個面試題的要求添加一些功能:非選中的圖像會縮小并且半透明顯示,添加上Adapter讓滑動人Item可以按需求增減坡垫。
最終我們實現(xiàn)一個類似的效果:
具體實現(xiàn)參考:CoverflowView.java
問題和優(yōu)化
這是一個簡單的實現(xiàn)方式梭灿,為什么要寫一個簡單的實現(xiàn)呢?我認(rèn)為這樣對于自己梳理知識(寫文章)和對于想學(xué)習(xí)UI開發(fā)的朋友都是最有利的冰悠,我們先動手堡妒,然后發(fā)現(xiàn)我們遇到的問題,然后把這些問題解決了溉卓,然后獲得提高皮迟!
Adapter添加上的子View如何計算高度和寬度?
本實例中我們寫死了子View的大小桑寨。可以添加fling實現(xiàn)更好的滑動體驗伏尼。
了解一些概念:VelocityTracker & Scroller.fling了解addView & addViewInLayout的區(qū)別,我們還沒有處理View的緩存的問題尉尾。
不需要每次都把所有的子View添加到ViewGroup爆阶,而只添加在可視區(qū)域能界能出來的View。當(dāng)子View滑出ViewGroup的可視區(qū)域時,如何處理辨图?同理班套,剛滑進(jìn)可視區(qū)時如何處理?如何通知外部選中項發(fā)生了變化徒役?
這個問題應(yīng)該不對實現(xiàn)吧孽尽。
這個實現(xiàn)還有很多可以優(yōu)化的地方, 比如性能上忧勿,現(xiàn)在可能感覺不出來杉女,但是當(dāng)我們的Item比較復(fù)雜時(現(xiàn)在我們只是一個ImageView),而且Adapter中的數(shù)據(jù)較多時鸳吸,就有可能會出現(xiàn)明顯的卡頓現(xiàn)象熏挎。像不像ListView遇到的問題,其實是一樣的晌砾,希望大家動手試試坎拐。
最后
有更好實現(xiàn)的,期待大家給我投稿养匈,之后有時間我會再公布一版優(yōu)化的版本哼勇。
未完待大家一起動手......