Vấn đề cơ bản là, bạn phải chờ pha vẽ cho các phép đo thực tế (đặc biệt là với các giá trị động như wrap_content
hoặc match_parent
), nhưng thường thì giai đoạn này chưa được hoàn thành onResume()
. Vì vậy, bạn cần một cách giải quyết để chờ đợi giai đoạn này. Có nhiều giải pháp khả thi khác nhau cho vấn đề này:
1. Nghe các sự kiện Vẽ / Bố cục: ViewTreeObserver
Một ViewTreeObserver bị sa thải cho các sự kiện vẽ khác nhau. Thông thường, đó OnGlobalLayoutListener
là những gì bạn muốn để có được phép đo, vì vậy mã trong trình nghe sẽ được gọi sau giai đoạn bố trí, vì vậy các phép đo đã sẵn sàng:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Lưu ý: Người nghe sẽ bị xóa ngay lập tức vì nếu không nó sẽ kích hoạt mọi sự kiện bố trí. Nếu bạn phải hỗ trợ ứng dụng SDK Lvl <16, hãy sử dụng ứng dụng này để hủy đăng ký người nghe:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Thêm một runnable vào hàng đợi bố trí: View.post ()
Không nổi tiếng lắm và giải pháp yêu thích của tôi. Về cơ bản chỉ cần sử dụng phương pháp bài của View với runnable của riêng bạn. Điều này về cơ bản xếp hàng mã của bạn sau khi đo, bố cục, v.v. như được nêu bởi Romain Guy :
Hàng đợi sự kiện UI sẽ xử lý các sự kiện theo thứ tự. Sau khi setContentView () được gọi, hàng đợi sự kiện sẽ chứa một thông báo yêu cầu chuyển tiếp, do đó, bất cứ điều gì bạn đăng lên hàng đợi sẽ xảy ra sau khi vượt qua bố cục
Thí dụ:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
Ưu điểm hơn ViewTreeObserver
:
- mã của bạn chỉ được thực thi một lần và bạn không phải vô hiệu hóa Trình quan sát sau khi thực thi có thể gây rắc rối
- cú pháp ít dài dòng
Người giới thiệu:
3. Ghi đè Phương thức onLayout của Lượt xem
Điều này chỉ thực tế trong một số trường hợp nhất định khi logic có thể được gói gọn trong chính khung nhìn, nếu không đây là một cú pháp khá dài dòng và rườm rà.
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight(); //height is ready
}
};
Cũng lưu ý rằng onLayout sẽ được gọi nhiều lần, vì vậy hãy cân nhắc những gì bạn làm trong phương thức hoặc vô hiệu hóa mã của bạn sau lần đầu tiên
4. Kiểm tra xem đã qua giai đoạn bố trí chưa
Nếu bạn có mã đang thực thi nhiều lần trong khi tạo ui, bạn có thể sử dụng phương thức lib v4 hỗ trợ sau:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
Trả về true nếu chế độ xem đã qua ít nhất một bố cục kể từ lần cuối được gắn vào hoặc tách ra khỏi cửa sổ.
Bổ sung: Lấy số đo xác định tĩnh
Nếu chỉ cần lấy chiều cao / chiều rộng được xác định tĩnh, bạn có thể thực hiện việc này với:
Nhưng lưu ý bạn, rằng điều này có thể khác với chiều rộng / chiều cao thực tế sau khi vẽ. Javadoc mô tả sự khác biệt một cách hoàn hảo:
Kích thước của một khung nhìn được thể hiện bằng chiều rộng và chiều cao. Một khung nhìn thực sự sở hữu hai cặp giá trị chiều rộng và chiều cao.
Cặp đầu tiên được gọi là chiều rộng đo và chiều cao đo. Các kích thước này xác định mức độ lớn mà một khung nhìn muốn nằm trong cha mẹ của nó (xem Bố cục để biết thêm chi tiết.) Các kích thước đo có thể thu được bằng cách gọi getMeasuredWidth () và getMeasuredHeight ().
Cặp thứ hai được gọi đơn giản là chiều rộng và chiều cao, hoặc đôi khi vẽ chiều rộng và chiều cao bản vẽ. Các kích thước này xác định kích thước thực của chế độ xem trên màn hình, tại thời gian vẽ và sau khi bố trí. Các giá trị này có thể, nhưng không phải khác với chiều rộng và chiều cao đo được. Chiều rộng và chiều cao có thể đạt được bằng cách gọi getWidth () và getHeight ().