日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

实践自定义UI—RLF...(RelativeLayout LinearLayout FrameLayout....)

發布時間:2025/6/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实践自定义UI—RLF...(RelativeLayout LinearLayout FrameLayout....) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
上一篇文章我們利用 View進行自定義UI,這篇我們將利用Android現有的UI進行自定義UI。我們利用現有的UI控件,主要是利用它們的一些屬性,并且根據這些屬性的改變可以達到我們預期的效果。還是看看今天我們實現的效果吧,No picture,it's so hard。效果圖如下所示,就是我們常見的Tab和SeekBar,看看今天怎么用現有的UI控件實現它;老樣子我們還是來一步一步分析吧。
效果圖

分解效果圖

?我們看到Horizontal和Vertical兩個Tab是不可以滑動的,只有通過點擊來觸發左右切換,在Tab的下面會有一個帶顏色的bar標志當前選中的位置。想這樣的UI目前現有的Android控件應該沒有可以直接使用的(據我的了解)。一般我們在實現這樣的UI時,我們會用TextView和一個帶顏色的View組合實現。這樣好像也可以,但是還是有一定的代碼量的。那么我們怎么用最少的代碼實現這樣的需求呢!首先我們看到左右切換的選中,類似于RadioButton這樣的控件——在多個選項中只能選取其中一個,但是RadioButton這樣的控件底部好像也沒有這樣的帶顏色的bar啊,難道還是要利用一個View和它組合使用嗎,那這樣還是太low了。我們想啊,既然底部沒有這樣一個bar,那我們可以讓RadioButton在底部畫一個啊。怎么畫?那當然是繼承它,在onDraw()方法里面畫啦。具體怎么畫,我相信畫一個矩形應該很簡單吧^_^。

?上面分析完了Tab的部分,這下我們來看看這個Seekbar吧,我們先看看下面分解的4張圖片。


第一條進度條
第二條進度條
游標
以上三個疊加效果

從上面的四張圖片可以看出,這個Seekbar是通過前面三張一個一個疊加過后達到第四張圖片的效果。當我們拖動小thumb(小圓球)滑動的時候,不斷的改變第二層上圓角矩形的寬度就可以達到想要的效果了。那么具體怎么實現,當然還是上代碼啦。

實現分解效果圖

1.實現Tab的切換效果

?上面我們分析了,需要實現Tab底部的效果主要是繼承RadioButton,并在onDraw()方法中繪制一個矩形就可以了,還是直接上代碼吧。

@Override protected void onDraw(Canvas canvas) {super.onDraw(canvas);int height = getMeasuredHeight();//the indicator's heightint indicatorHeight = getResources().getDimensionPixelSize(R.dimen.radio_button_indicator_height);if (isChecked()){mPaint.setColor(getCurrentTextColor());}else {mPaint.setColor(Color.TRANSPARENT);}canvas.drawRect(0, height - indicatorHeight, getMeasuredWidth(), height, mPaint); }

這里我們設置了選中色塊的高度,再調用drawRect()方法繪制矩形(選中色塊)。這里簡單介紹一個這個方法

drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)

先看看下面的圖解吧。


矩形繪制示意圖

結合上面的圖解,我們這里把top的值設為height - indicatorHeight,這個height為整個RadioButton的高度,由圖應該可以很清楚的知道top的坐標計算方法了。我們在RadioButton選中的時候通過Paint的值設置選中顏色,當處于未選中狀態時設置為透明色,并且繪制同一塊區域,達到切換的效果。

2.實現Seekbar

?在分析Seekbar的時候,我們把它分解成了幾個層次的疊加,那接下來我們的任務就是實現這些層次的疊加。我們這部分是通過現有的UI控件實現這個效果的,那么我們用哪一個UI控件可以實現層次的疊加呢,那當然只有FrameLayou和RelativeLayout啦!那到底用FrameLayout還是RelativeLayout呢?這里我們使用RelativeLayout,對于FrameLayout的使用可以自行實踐。

(1)實現第一層圓角——progressbar


第一條進度

?那我們這一層用什么實現呢,這里我們可以使用Andorid UI控件中的LinearLayout、FrameLayou等都可以,但是我們這里使用ViewGroup的子類——LinearLayout(當然也可以選取其他的),這樣我們可以對這一層進行擴展,在里面添加TextView、ImageView等。那么怎么實現圓角呢,當時是使用drawble進行配置的,但是對于使用drawable進行配置是有問題的——不能代碼控制圓角的大小,這個問題導致可擴展性太差。那怎么解決呢,當然得想辦法啊,最后找到了使用GradientDrawable,這里我想說的就是,我們在自定義的過程中總會出現問題,然后不停的找到具體的解決方法,一步一步實現。其實其他的編程問題都是這樣的。好了,我們這里還是直接看看具體代碼吧,如下:

mFirstBar = new LinearLayout(context);GradientDrawable drawable = new GradientDrawable();drawable.setColor(Color.parseColor("#FFBB33"));drawable.setCornerRadius((float) mProgressHeight / 2);mFirstBar.setBackgroundDrawable(drawable);//mFirstBar.setBackgroundResource(R.drawable.firtbar_bkg);mFirstBarLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mProgressHeight);mFirstBarLp.addRule(CENTER_IN_PARENT);mFirstBar.setClickable(false);addView(mFirstBar, mFirstBarLp);

好了,第一層的實現應該很簡單吧。

(2)實現第二層圓角——secondProgressbar


第二條進度

?其實secondProgressbar的實現基本上同progressbar的實現類似,還是直接上代碼吧

mSecondBar = new LinearLayout(context);GradientDrawable secondDrawable = new GradientDrawable();secondDrawable.setColor(Color.parseColor("#99CC00"));secondDrawable.setCornerRadius((float)mProgressHeight/2);mSecondBar.setBackgroundDrawable(secondDrawable);mSecondBarLp = new RelativeLayout.LayoutParams(mThumbRadius, mProgressHeight);//mSecondBarLp.leftMargin = 0;mSecondBarLp.addRule(CENTER_VERTICAL);//mSecondBarLp.addRule(LEFT_OF, THUMB_ID);mSecondBarLp.addRule(ALIGN_PARENT_LEFT);addView(mSecondBar, 1, mSecondBarLp);mSecondBar.setClickable(false);

這里我們看到了,在創建LayoutParams的時候,我們設置的width的大小為圓角半徑的大小,為什么要這么做?這里還是先解釋一下吧,這樣做的目的主要是將secondProgressbar的最右端總是在thumb的中心位置,這里記住這一點后面我們在介紹。

(3)實現游標——thumb

?其實thumb很簡單啦,就是一個圓形的View。這里直接使用TextView,不要問我為什么——我任性$_$。直接看代碼吧。

mThumb = new TextView(context);GradientDrawable thumb = new GradientDrawable();thumb.setColor(Color.parseColor("#33b5e5"));thumb.setCornerRadius((float)mThumbRadius);mThumb.setBackgroundDrawable(thumb);mThumbLp = new RelativeLayout.LayoutParams(mThumbRadius*2, mThumbRadius*2);mThumbLp.addRule(CENTER_VERTICAL);mThumbLp.addRule(ALIGN_PARENT_LEFT);mThumbLp.leftMargin = 0;addView(mThumb, mThumbLp);mThumb.setId(THUMB_ID);mThumb.setGravity(Gravity.CENTER);if (mThumbTextSize != 0)mThumb.setTextSize(mThumbTextSize);

這里在我們使用TextView,我們還可以在上面顯示一些信息,擴展性更好,當然你也可以利用其他UI控件,設置你需要的UI!

(4)實現滑動——Seekbar

?好了,上面我們分解的圖都實現了,現在應該要實現滑動了吧!那么怎么實現按住Thumb就會滑動,并且secondProgressbar和滑動,同時顯示當前的進度。當然是使用監聽OnTouchEvent事件啦,根據滑動的distance不斷更新thumb和secondProgressbar的參數,讓他們動起來。那這里就直接實現RelativeLayout的OnTouchEvent方法,還是先看代碼吧,如下:

@Override public boolean onTouchEvent(MotionEvent event) {int action = MotionEventCompat.getActionMasked(event);boolean isDraged = false;Rect rect = new Rect();mThumb.getHitRect(rect);switch (action){case MotionEvent.ACTION_DOWN:float x = event.getX();float y = event.getY();boolean contain = rect.contains((int)x, (int)y);if (contain){mLastMotionX = event.getX();isDraged = true;}break;case MotionEvent.ACTION_MOVE:dragThumb(event.getX());break;case MotionEvent.ACTION_UP:break;}return isDraged; }private void dragThumb(float x){float distance = (x - mLastMotionX);mLastMotionX = x;mThumbLp.leftMargin = (int) (mThumbLp.leftMargin + distance);mSecondBarLp.width = (int) (mSecondBarLp.width + distance);LogUtils.LogD(TAG, " horizontal current distance == " + distance);//confirm this thumb is show, no anywhere is hideif (mThumbLp.leftMargin <= 0) {mThumbLp.leftMargin = 0;mSecondBarLp.width = mThumbRadius;} else if (mThumbLp.leftMargin >= getMeasuredWidth() - mThumbRadius * 2) {mThumbLp.leftMargin = getMeasuredWidth() - mThumbRadius * 2;mSecondBarLp.width = getMeasuredWidth() - mThumbRadius;}updateViewLayout(mThumb, mThumbLp);updateViewLayout(mSecondBar, mSecondBarLp); }

這里我們實現的是整個RelativeLayout的OnTouchEvent方法,所以它的touch事件是針對整個RelativeLayout的。所以這里我們要做一下過濾,點擊范圍在不在thumb上面,只有點擊和拖動都在thumb上面這次的touch對thumb才有效。當確定拖動有效的時候,在開始初始化的時候,設置了thumb相對于父控件為ALIGN_PARENT_LEFT,所以通過改變mThumbLp.leftMargin就可以改變thumb于左邊的距離啦。對于secondProgressbar,只要改變mSecondBarLp.width的大小就可以改變它的寬度,最后調用updateViewLayout()方法更新UI。這里我們要注意兩點:
1.防止thumb滑動到最右端時超出邊界。
2.防止thumb滑動回來到最左端時超出邊界。

好了,到這里通過簡單的介紹,我們將這個Seekbar的基本功能完成。

總結

?上面我們利用Android控件實現了一個簡單的Seekbar,現在簡單的總結一下:

1.和實踐自定UI—View的時候一樣,我們還是把這個Seekbar進行了分解,然后一步一步實現。

2.在自定義的過程中我們會遇到很多問題,我在這里遇到了這些問題:圓角怎么可以用代碼控制、在開始的時候我沒有利用RelativeLayou的onTouchEvent方法實現滑動,而是將onTouchEvent事件直接set在thumb上面,結果滑動的時候出現了問題(有興趣的可以自己試試看看是什么問題)....。這里面遇到了很多問題,但都一個一個擊破,所以我們在自定UI的時候不要心急,一點一點將沒有問題解決,最后就會實現你想要的效果。

3.這里只是通過這個例子分析怎樣去利用Android UI 自定義我們自己需要的UI。這里只是引導,更多的還是靠實踐、實踐、實踐...。重要的事說三遍^_^

好了,國際慣例,可以自己練習一下垂直方向的Seekbar,如下圖:


垂直效果

?最后還是放上代碼地址吧

如何利用View自定義UI請閱讀實踐自定UI—View

如何利用ViewGroup自定義UI請閱讀實踐自定義UI-ViewGroup

希望在Android學習的路上,大家共同成長!

總結

以上是生活随笔為你收集整理的实践自定义UI—RLF...(RelativeLayout LinearLayout FrameLayout....)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。