編輯:Android編程入門
前面幾節,我們重點討論了自定義View的三板斧,這節我們來討論自定義ViewGroup,為什麼要自定義ViewGroup,其實就是為了更好的管理View。
自定義ViewGroup無非那麼幾步:
Ⅰ、重寫OnMeasure()方法,測試子控件的大小。
Ⅱ、重寫onLayout()方法,計算子控件的布局。
Ⅲ、在onDraw()方法中,繪制子控件,可有可無。
Ⅳ、監聽onTouch事件,響應屏幕觸摸事件。
相應思維導圖如下所示:

連篇累牍的說了這麼多,我們通過一個小案例來理解這個自定義ViewGroup把,看看如何實現ViewGroup。
簡單的黏性ScrollView
簡單概述
這是一個原生scrollView效果非常類似的效果,他可以像scrollView一樣上下滑動的效果,不過我們增加了一個黏性效果。何為黏性效果了?即當一個子View向上滑動大於一定距離的時候,它將自動向上滑動,顯示下一個子View。同理,如果一個子View滑動距離小於某一個距離,它將滾回到原始的位置。
實現思路
投籃要找角度,控件要找思路。我們來分析要實現此自定義ViewGroup的基本思路了:
Ⅰ、在OnMeasure()方法中,對每個子控件的大小進行測量了。
Ⅱ、在OnLayout()方法中,對每個要顯示控件的位置進行計算。
Ⅲ、緊接著,就是在OnTouchEvent()方法,監聽著手勢觸摸事件,判斷它是上滑還是下滑,判斷它的滑動距離是否大於我們設定的值,如果大於這個值,就將它移動到下一個子View,否則,滾回到原來的位置。
有了這樣的思路之後,我們只需要所做的是按部就班實現代碼編寫
具體實現
第一步、進行一些變量的初始化,代碼如下:
private void init(Context context) {
WindowManager manager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(displayMetrics);
mScreenHeight = displayMetrics.heightPixels;
mScroller = new Scroller(context);
}
獲取屏幕高度作為每個控件的高度,將scroller控件進行初始化。
第二步 、實現控件的測量,代碼如下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
我們看到每個子控件的大小與父控件的大小保持一致,這樣才能形成滾動的效果。
第三步、將子控件從上到下依次排列開來,代碼如下所示:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
layoutParams.height = mScreenHeight * count;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);
}
}
}
我們可以清晰的看到,如果將其子控件進行從上到下依次排列,這個子控件占一頻,這樣,才能形成可以上下滾動的必要條件。
第四步、監聽手勢事件,源代碼如下:
@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = y;
mStart = getScrollY();
break;
case MotionEvent.ACTION_MOVE:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
int dy = y - mLastY;
if (getScrollY()< 0) {
dy = 0;
} else if (getScrollY()> getHeight() - mScreenHeight) {
dy = 0;
}
scrollBy(0, dy);
mLastY = y;
break;
case MotionEvent.ACTION_UP:
mEnd = getScrollY();
int delta = mEnd - mStart;
if (delta > 0) {
if (delta < mScreenHeight / 3) {
mScroller.startScroll(0, getScrollY(), 0, -delta);
} else {
mScroller.startScroll(0, getScrollY(), 0, mScreenHeight
- delta);
}
} else {
if (Math.abs(delta) < mScreenHeight / 3) {
mScroller.startScroll(0, getScrollY(), 0, -delta);
} else {
mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight
- delta);
}
}
break;
default:
break;
}
return true;
}
事後總結
其實,在這個事件監聽中就做了三件事件
①、根據手勢按下、抬起的距離進行判斷,判斷手勢到底是上滑還是下滑。
②、如果手勢滑動的距離,小於小於相應的阈值(這裡為屏幕高度的三分之一)以後,就滾回到原來的位置,否則自動滑入下一個子View。
③、在手指移動事件,使這個控件能夠隨著手勢的滑動而自由的移動。但是,我們要做好相應臨界值判斷,判斷其是否小於0或者大於屏幕高度,就不進行滑動。
最終效果
這個控件最終運行的效果為:

這就是,我對自定義viewGroup控件的一定總結。本人才疏學淺,懇請大家指教。
Android入門:綁定本地服務
一、綁定服務介紹 前面文章中講過一般的通過startService開啟的服務,當訪問者關閉時,服務仍然存在;但是如果存在這樣一種情況:訪問者需要與服務進行通信,
Android 輪換頁面+TabHost 實例
最終效果展示: 首先我們需要一個ViewPager控件,不過可以發現在左側的控件列表中並沒有這個控件 這時我們要去升級包中查看
Android 自定義ViewGroup的步驟
前面幾節,我們重點討論了自定義View的三板斧,這節我們來討論自定義ViewGroup,為什麼要自定義ViewGroup,其實就是為了更好的管理View。 自定義Vie
andorid 手機外部儲存操作
.xml<?xml version=1.0 encoding=utf-8?><LinearLayout xmlns:android=http://sch