2011-09-15 36 views
6

Tôi đang viết một ứng dụng với mục đích duy nhất là cố gắng hiểu cách phân cấp chế độ xem trong Android hoạt động. Tôi đang có một số vấn đề thực sự khắc nghiệt trong nó ngay bây giờ. Tôi sẽ cố gắng súc tích trong lời giải thích của tôi ở đây.Cố gắng hiểu cấu trúc phân cấp xem

Thiết lập:

Hiện tại tôi có ba Chế độ xem. 2 là ViewGroups và 1 chỉ là View. Hãy nói rằng họ theo thứ tự này:

TestA extends ViewGroup 
    TestB extends ViewGroup 
    TestC extends View 
    TestA->TestB->TestC 
    Where TestC is in TestB and TestB is in TestA. 

Trong Activity của tôi, tôi chỉ đơn giản là hiển thị các quan điểm như vậy:

TestA myView = new TestA(context); 
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 
setContentView(myView); 

vấn đề:

  1. Phương pháp onDraw(Canvas canvas) của Testa là không bao giờ gọi là. Tôi đã nhìn thấy một vài giải pháp này nói rằng quan điểm của tôi không có bất kỳ kích thước (chiều cao/chiều rộng = 0), tuy nhiên, đây không phải là trường hợp. Khi tôi ghi đè onLayout(), tôi nhận được kích thước bố cục của tôi và chúng đúng. Ngoài ra, getHeight()/Width() chính xác như chúng cần. Tôi cũng có thể ghi đè lên số dispatchDraw() và nhận các lượt xem cơ bản của mình để vẽ.

  2. Tôi muốn tạo ảnh động một đối tượng trong TestB. Theo truyền thống, tôi sẽ ghi đè lên phương pháp onDraw() trên cuộc gọi invalidate() trên chính nó cho đến khi đối tượng kết thúc hoạt ảnh mà nó được cho là phải làm. Tuy nhiên, trong TestB, khi tôi gọi invalidate() chế độ xem không bao giờ được vẽ lại. Tôi có ấn tượng rằng đó là công việc của chế độ xem cha mẹ của tôi để gọi lại phương thức onDraw(), nhưng chế độ xem gốc của tôi không gọi lại số dispatchDraw().

Tôi đoán câu hỏi của mình là, tại sao phương pháp onDraw() của bố mẹ tôi không bao giờ được gọi để bắt đầu? Phương pháp nào trong chế độ xem cha mẹ của tôi được cho là sẽ được gọi khi một trong số đó là con cái mất hiệu lực? Cha mẹ là người chịu trách nhiệm đảm bảo con của nó bị lôi cuốn hay Android có chăm sóc điều đó không? Nếu Android trả lời invalidate(), tại sao số TestB của tôi không bao giờ bị rút lại?

Trả lời

5

Ok, sau khi một số nghiên cứu và rất nhiều thử, tôi đã phát hiện ra tôi đã làm ba điều sai về vấn đề # 2. Rất nhiều câu trả lời đơn giản nhưng không rõ ràng lắm.

  • Bạn cần ghi đè onMeasure() cho mỗi chế độ xem. Trong vòng onMeasure(), bạn cần gọi số measure() cho mỗi trẻ em có trong số ViewGroup chuyển vào MeasureSpec mà trẻ cần.

  • Bạn cần gọi số addView() cho mỗi số con bạn muốn bao gồm. Ban đầu, tôi chỉ đơn giản là tạo ra một đối tượng xem và sử dụng nó trực tiếp.Điều này cho phép tôi vẽ nó một lần, nhưng quan điểm không được bao gồm trong cây xem, do đó khi tôi gọi là invalidate() nó không làm mất hiệu lực cây xem và không vẽ lại. Ví dụ:

Trong Testa:

TestB childView; 
TestA(Context context){ 
    ****** setup code ******* 
    LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
    childView = new TestB(context); 
    childView.setLayoutParams(params); 
} 

@Override 
protected void dispatchDraw(Canvas canvas){ 
    childView.draw(canvas); 
} 

này sẽ rút ra những cái nhìn con một lần. Tuy nhiên, nếu chế độ xem đó cần cập nhật cho hoạt ảnh hoặc bất kỳ thứ gì, thì đó là nó. Tôi đặt addView(childView) trong hàm tạo của TestA để thêm nó vào cây xem. mã cuối cùng là như vậy:

TestB childView; 
TestA(Context context){ 
    ****** setup code ******* 
    LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
    childView = new TestB(context); 
    childView.setLayoutParams(params); 
    addView(childView); 
} 

@Override 
protected void dispatchDraw(Canvas canvas){ 
    childView.draw(canvas); 
} 

Ngoài ra, tôi có thể ghi đè lên dispatchDraw(Canvas canvas) như vậy nếu tôi đã có rất nhiều em nhỏ để vẽ, nhưng tôi cần một số yếu tố tùy chỉnh giữa mỗi vẽ như đường lưới hoặc một cái gì đó.

@Override 
protectd void dispatchDraw(Canvas canvas){ 
    int childCount = getChildCount(); 
    for(int i = 0; i < size; i++) 
    { 
     drawCustomElement(); 
     getChildAt(i).draw(canvas); 
    } 
} 
  • Bạn phải ghi đè onLayout() (đó là trừu tượng trong ViewGroup dù sao, vì vậy nó cần anyway). Trong phương thức này, bạn phải gọi layout cho mọi trẻ em. Ngay cả sau khi thực hiện hai điều đầu tiên, quan điểm của tôi sẽ không làm mất hiệu lực. Ngay sau khi tôi đã làm điều này, tất cả mọi thứ đã làm việc hoàn hảo.

CẬP NHẬT: Vấn đề # 1 đã được giải quyết. Một giải pháp cực kỳ đơn giản nhưng không quá rõ ràng.

Khi tôi tạo một phiên bản TestA, tôi phải gọi setWillNotDraw(false) nếu không Android sẽ không rút ra vì lý do tối ưu hóa. Vì vậy, thiết lập đầy đủ là:

TestA myView = new TestA(context); 
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 
myView.setWillNotDraw(false); 
setContentView(myView); 
+0

bạn có thể chia sẻ dự án demo này của Viewgroup trong blog của bạn hoặc một nơi nào đó nó sẽ rất hữu ích .. Cảm ơn bạn đời .. – user1201239

+0

tôi có cần thêm childView ngay cả khi chúng tôi chỉ định nó trong XML không? – user1201239

+0

Tôi xin lỗi. Tôi không có blog hoặc bất cứ thứ gì để tải lên. Tôi sẽ cố gắng hết sức hữu ích nhất có thể. Để trả lời câu hỏi đầu tiên của bạn, không. Khi bạn thổi phồng xml, con được chứa trong 'ViewGroup'. Đầu tiên bạn có thể lấy nó là 'onFinishInflate()'. Sau đó bạn có một sự lựa chọn. Hoặc là đưa con bạn qua phương thức 'getChildAt (int index)' hoặc sử dụng 'findViewById (int id)'. Chỉ mục sẽ là thứ tự các trẻ em được đặt trong xml. Tôi không biết cách lập chỉ mục hoạt động với trẻ em trong trẻ em. – DeeV

2

Đây không phải là câu trả lời trực tiếp, mà là here is a fantastic tutorial về cách vẽ chế độ xem tùy chỉnh và cung cấp cho bạn một sự cố tuyệt vời về cách tạo hoạt ảnh cho chế độ xem. Mã rất đơn giản và sạch sẽ quá.

Hy vọng điều này sẽ hữu ích!

+0

Cảm ơn. Điều này đã không giải quyết được vấn đề của tôi nhưng nó đã giúp đỡ trong việc dẫn đến giải pháp. – DeeV

Các vấn đề liên quan