Bài tập 21: Thực hành về Tab Selector trong Android


Tab Selector giống như Property Sheet trong Visual C, giống như Tab Control C#, hay trong Java:

21_tab_0

– Tôi sẽ làm một ví dụ cụ thể về Tab Selector để bạn có thể thực hành lại và hiểu được vấn đề.

– Đối với Android, mỗi Tab bạn nên thiết kế trên một Layout khác nhau, rồi trong Main Layout bạn include các tab đó vào (Tức là nếu như ứng dụng bạn có 3 Tab con thì sẽ tạo 3 Layout khác nhau rồi include chúng vào Main layout, chứ đừng thiết kế tất tần tật trong một Main Layout nó sẽ gây khó khăn trong việc sửa lỗi ).

– Tôi trình bày sơ qua lý thuyết về Tab selector:

+ Tab selector gồm có 3 phần: Tab Host, Tab WidgetsFrameLayout.

21_tab_1

+Tab Host: Là Container chính chứa các Tab buttons và Tab contents

+Tab Widget: Để định dạng cho các Tab buttons : Nhãn, Icon…

+FrameLayout: là Container để chứa các layout cho Tab contents, ta chỉ có thể dùng FrameLayout cho Tab contents, không thể dùng các loại Layout khác. Nếu bạn thắc mắc tại vì sao lại là FrameLayout mà không phải là các Layout khác? thì Tôi chỉ nói đơn giản thế này: Cho dù bạn có nhấn vào các Tab nào đi nữa thì layout tương ứng với mỗi Tab mà bạn vừa nhấn vào cũng chỉ xuất hiện cùng một chỗ trên màn hình điện thoại, điều này chỉ có FrameLayout mới giải quyết được.

*** Bây giờ bạn hãy xem hình minh họa về giao diện trong bài ví dụ Tab Selector của Tôi như sau:

21_tab_3– Như hình trên thì bạn thấy đó: Tab đầu tiên “1-CALCULATOR” là giao diện cho phép tính công trừ nhân chia, Tab thứ 2 “2-HISTORY” dùng để hiển thị danh sách các phép toàn đã thực hiện.

– Bạn xem cấu trúc tổng quan của ứng dụng:

21_tab_4-Vì ứng dụng của Tôi có 2 Tab nên Tôi sẽ tạo 2 tabs: tab1_layout.xmltab2_layout.xml, 2 tabs này sẽ được include vào main layout activity_main.xml, vậy tổng cộng Tôi có 3 Layout.

– Ta vào xem main layout (activity_main.xml):

– xem Outline để dễ tưởng tượng:

21_tab_5-Còn đây là source XML:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<TabHost
 android:id="@android:id/tabhost"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >
 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >
 <TabWidget
 android:id="@android:id/tabs"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 </TabWidget>
 <FrameLayout
 android:id="@android:id/tabcontent"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >
 <LinearLayout
 android:id="@+id/tab1"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 <include layout="@layout/tab1_layout"/>
 </LinearLayout>
 <LinearLayout
 android:id="@+id/tab2"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >
 <include layout="@layout/tab2_layout"/>
 </LinearLayout>
 </FrameLayout>
 </LinearLayout>
 </TabHost>

</LinearLayout>

– Bạn nhìn vào dòng lệnh 30 và 36:

<include layout=”@layout/tab1_layout”/>

<include layout=”@layout/tab2_layout”/>

Đó chính là cách include một layout này vào trong một layout khác.

– Tiếp tục ta xem tab1_layout.xml, Tôi lấy lại bài tập trước về cộng trừ nhân chia:


<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/TableLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:stretchColumns="*" >

<TableRow
 android:id="@+id/tableRow1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_span="4"
 android:background="#5B8020"
 android:gravity="center"
 android:text="Cộng trừ nhân chia"
 android:textColor="#FFFFFF"
 android:textSize="20sp" />
 </TableRow>

<TableRow
 android:id="@+id/tableRow2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Số a:" />

<EditText
 android:id="@+id/editsoa"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_span="3"
 android:ems="10"
 android:inputType="number" >

<requestFocus />
 </EditText>
 </TableRow>

<TableRow
 android:id="@+id/tableRow3"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView3"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Số b:" />

<EditText
 android:id="@+id/editsob"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_span="3"
 android:ems="10"
 android:inputType="number" />
 </TableRow>

<TableRow
 android:id="@+id/tableRow4"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<Button
 android:id="@+id/btncong"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="+" />

<Button
 android:id="@+id/btntru"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="-" />

<Button
 android:id="@+id/btnnhan"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="*" />

<Button
 android:id="@+id/btnchia"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="/" />
 </TableRow>

<TableRow
 android:id="@+id/tableRow5"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/txtketqua"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_span="4"
 android:background="#5B8020"
 android:textColor="#FFFFFF"
 android:textSize="25sp" />
 </TableRow>

</TableLayout>

– Và xem tiếp tab2_layout.xml, đơn giản là chỉ có 1 ListView chứa danh sách các phép toán đã thực hiện bên Tab1:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

<ListView
 android:id="@+id/lvhistory"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 </ListView>

</LinearLayout>

– Giờ bạn xem MainActivity để biết được cách cấu hình Tabhost:


package tranduythanh.com;

import java.util.ArrayList;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
 //Enum để thực hiện phép toán
 enum Operator
 {
 Cong,//phép cộng
 Tru,//phép trừ
 Nhan,//phép nhân
 Chia//phép chia
 }
 Button btncong,btntru,btnnhan,btnchia;
 EditText editsoa,editsob;
 TextView txtkq;
 ListView lvHistory;
 ArrayList<String>array_operator=new ArrayList<String>();
 ArrayAdapter<String>adapter=null;
 //Variable in listener
 OnClickListener myclick=new OnClickListener() {

@Override
 public void onClick(View arg0) {
 switch(arg0.getId())
 {
 case R.id.btncong:
 {
 processOperator(Operator.Cong);
 }
 break;
 case R.id.btntru:
 {
 processOperator(Operator.Tru);
 }
 break;
 case R.id.btnnhan:
 {
 processOperator(Operator.Nhan);
 }
 break;
 case R.id.btnchia:
 {
 processOperator(Operator.Chia);
 }
 }
 }
 };
 /**
 * Hàm xử lý phép toán theo operator
 * @param op
 */
 public void processOperator(Operator op)
 {
 String sa=editsoa.getText()+"";
 String sb=editsob.getText().toString();
 int a=Integer.parseInt(sa);
 int b=Integer.parseInt(sb);
 String kq="";
 switch(op)
 {
 case Cong:
 kq=a+" + "+b +" = "+(a+b);
 break;
 case Tru:
 kq=a+" - "+b +" = "+(a-b);
 break;
 case Nhan:
 kq=a+" * "+b +" = "+(a*b);
 break;
 case Chia:
 if(b!=0)
 kq=a+" / "+b +" = "+(a*1.0/b);
 else
 kq="b phai khac 0";
 break;
 default:
 kq="Invalid operator!";
 }
 txtkq.setText(kq);
 array_operator.add(kq);
 adapter.notifyDataSetChanged();
 }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 loadTabs();
 doFormWidgets();
 }
 //Cấu hình tab
 public void loadTabs()
 {
 //Lấy Tabhost id ra trước (cái này của built - in android
 final TabHost tab=(TabHost) findViewById
 (android.R.id.tabhost);
 //gọi lệnh setup
 tab.setup();
 TabHost.TabSpec spec;
 //Tạo tab1
 spec=tab.newTabSpec("t1");
 spec.setContent(R.id.tab1);
 spec.setIndicator("1-Calculator");
 tab.addTab(spec);
 //Tạo tab2
 spec=tab.newTabSpec("t2");
 spec.setContent(R.id.tab2);
 spec.setIndicator("2-History");
 tab.addTab(spec);
 //Thiết lập tab mặc định được chọn ban đầu là tab 0
 tab.setCurrentTab(0);
 //Ở đây Tôi để sự kiện này để các bạn tùy xử lý
 //Ví dụ tab1 chưa nhập thông tin xong mà lại qua tab 2 thì báo...
 tab.setOnTabChangedListener(new
 TabHost.OnTabChangeListener() {
 public void onTabChanged(String arg0) {
 String s="Tab tag ="+arg0 +"; index ="+
 tab.getCurrentTab();
 Toast.makeText(getApplicationContext(),
 s, Toast.LENGTH_LONG).show();}
 });
 }
 //Khởi tạo các đối tượng và gán ADapter cho ListView
 public void doFormWidgets()
 {
 btncong=(Button) findViewById(R.id.btncong);
 btntru=(Button) findViewById(R.id.btntru);
 btnnhan=(Button) findViewById(R.id.btnnhan);
 btnchia=(Button) findViewById(R.id.btnchia);
 editsoa=(EditText) findViewById(R.id.editsoa);
 editsob=(EditText) findViewById(R.id.editsob);
 txtkq=(TextView) findViewById(R.id.txtketqua);
 lvHistory=(ListView) findViewById(R.id.lvhistory);
 btncong.setOnClickListener(myclick);
 btntru.setOnClickListener(myclick);
 btnnhan.setOnClickListener(myclick);
 btnchia.setOnClickListener(myclick);
 adapter=new ArrayAdapter<String>
 (this,
 android.R.layout.simple_list_item_1,
 array_operator);
 lvHistory.setAdapter(adapter);
 }
}

– Tôi có giải thích sơ qua trong coding cách tạo tab, bạn hãy cố gắng làm lại để hiểu nó.

– Bao nhiêu tab không quan trọng, cuối cùng thì cũng chỉ đưa về xử lý bình thường như chỉ có 1 màn hình.

– Bạn  có thể tải coding mẫu ở đây: http://www.mediafire.com/?0xyr6ooi066dhiw

– Bài tập kế tiếp bạn sẽ học về MenuContext menu, 2 control này rất ưa chuộng nên ta phải biết nó.

– Chúc bạn thành công.

17 responses

  1. thank bạn rất nhiều..bài viết rất ý nghĩa.mình ghé thăm web thường xuyên để đọc bài của bạn..

  2. Thầy ơi khi chạy nó chỉ hiển thị ra tab1 và tab 2 thôi.click vào 2 cái đó cũng chẳng hiện lên layout của 2 tab là sao?

    1. Mình cũng giống bạn.k hiểu sao nữa

  3. Thầy cho em hỏi mình dùng
    final TabHost tab=(TabHost) findViewById(android.R.id.tabhost);

    final TabHost tab=(TabHost) findViewById(R.id.tabhost);
    có khác biệt gì không? Trong ví dụ của thầy em dùng 2 cách đều chạy được.
    Cảm ơn thầy!

    1. Lê Xuân Đoàn | Reply

      Mình giải thích thế này k biết đúng chưa,nhưng qua nhiều vd mình nghĩ vậy
      có 2 class R trong android là R có sẵn của phiên bản android để code- android.R và R do app bạn code tạo ra .
      android.R.id.tabhost là lấy tabhost từ trong R của thư viện có sẵn đó
      R.id.tabhost là lấy tab host từ trong R do app bạn code tạo ra

    2. 1 là bạn dùng id của hệ thống do Android có sẵn findViewById(android.R.id.tabhost)
      2 là bạn dùng id tự mình định nghĩa …findViewById(R.id.tab_host)

    3. Nếu trong file layout vẫn khai báo là @android:id/tabhost thì findViewById(R.id.tabhost) sẽ báo lỗi ngay.

  4. Phạm Ngọc Bình | Reply

    Nhưng bài của thầy rất chi là chi tiết. và dễ hiễu .

  5. Thầy ơi cho e hỏi tại sao khi tính xong bên tab1 ta
    chọn vào tab2 không thấy có hostory gì ạ.chỉ có màn hình trống

    1. Em kiểm tra kỹ xem đã viết sự kiện cho tab chưa?

  6. Thầy ơi!!!
    Tại sao nó cứ lỗi ở tab.setup(); ạ????

  7. Em kiểm tra đặt id và loại dữ liệu trong xml layout đúng quy tắc hay chưa? và lỗi thì cụ thể là lỗi gì thì mọi người mới biết sửa cho em được.

    1. Cảm Ơn Thầy ạ!!!
      Em nhầm id….

  8. Thầy ời ,bây giờ e thay listView bằng GridView.Sao e findViewById(R.id.gridView) một layout đã tạo săn (đã include vào layout main) mà nó ko gọi đc id của gridview đó

    1. Đc rồi thầy ạ

  9. Thầy cho em hỏi làm sao set color được cho text trong spec.setIndicator với ạ?

Leave a reply to chauphi90 Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.