2018年3月16日 星期五

Java:讀取CSV檔內容寫入PDF

這支java檔,可以讀取csv檔案內的內容,並且把內容寫入pdf內

1.需要掛載itextpdf.jar檔

2.準備好CSV檔


3.程式碼


import java.io.*;
import java.util.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import com.itextpdf.text.Document.*;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

class loadCSV 
{
 static String  filePath="D:\\LoadCSV";
 static String fileName="";
 static Vector<String[]> vData = new Vector<String[]>();
 public static void main(String[] args) throws Throwable
 {
  File f = new File(filePath);
  File[] arrF = f.listFiles();
  for(int i = 0; i < arrF.length; i++) {
   if (arrF[i].getName().toUpperCase().indexOf(".CSV") != -1) {
    fileName = arrF[i].getName();
   } 
  }
  System.out.println(fileName);
  File fr = new File(filePath + "/" + fileName);
  InputStreamReader read = new InputStreamReader (new FileInputStream(fr), "big5");
  BufferedReader br = new BufferedReader(read);
  String line = "";
  
  
  while ((line = br.readLine()) != null) {
   
   System.out.println(line);

   line = line.replace("\",\"", "@split@");
   String[] arrLine = line.split("@split@");
   String meid = arrLine[0];
   System.out.println("========"+meid);
   String name=arrLine[1];
   String tel=arrLine[2];
   vData.add(new String[]{meid,name,tel});
  }

  read.close();
  br.close();
  System.out.println(vData.size());

  Document document = new Document(PageSize.A4, 4f, 0f, 50f, 0f);
  PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filePath + "/tmp" + ".pdf"));
  document.open();
  document.newPage();
  //建立PdfPTable物件並設定其欄位數
  PdfPTable table = new PdfPTable(2);
  //設定table的寬度
  table.setWidthPercentage(100f);
  //設定每個欄位的寬度
  table.setWidths(new float[]{0.20f, 0.20f});
  PdfPCell title = new PdfPCell(new Phrase("Table's Title"));
  //合併儲存格
  title.setColspan(2);
  //水平置中
  title.setHorizontalAlignment(Element.ALIGN_CENTER);
  //沒有外框線
  title.setBorder(Rectangle.NO_BORDER);

  table.addCell(title);

  for(int i=1;i<vData.size();i++){
   String[] idata = vData.get(i);
   PdfPCell cell_1 = new PdfPCell();
   for(int x=0;x<idata.length ; x++){
    if((vData.size()-1)%2!=0&&i==vData.size()-1){
     
     cell_1.setColspan(2);
     
    }
    cell_1.addElement(new Phrase(idata[x]));
    
    
    
   }
   
   table.addCell(cell_1);
   
  }

//  //設定第一個欄位的內容
//  PdfPCell cell_1 = new PdfPCell();
//  cell_1.addElement(new Phrase("Column 1"));
//  cell_1.addElement(new Phrase("Column 1"));
//  table.addCell(cell_1);
//  
//
//  //設定第二個欄位的內容
//  PdfPCell cell_2 = new PdfPCell();
//  cell_2.addElement(new Phrase("Column 2"));
//  cell_2.addElement(new Phrase("Column 2"));
//  table.addCell(cell_2);

  
  document.add(table);

  document.close();
  writer.close();

  
  
 }
}



2017年12月17日 星期日

Android:GitHub上受歡迎的Android UI Library

常常在開發時,最頭痛的就是設計元件的UI了,現在有很多網友做好的第三方library,只要在gradle文件中貼上lib的來源,就可以開始使用別人設計好的lib了。

介紹一個網站,這個網站整合了許多在GitHub上一些熱門的library:红鸟网络Android团队Blog

2017年8月13日 星期日

PHP與MySQL登入範例

此範例是以HTML的網頁做為登入頁面,並透過PHP程式連接MySQL資料庫,然後再以PHP網頁做為輸出頁面
範例的網址:http://tomchen263.000webhostapp.com/LoginExample_Web/login.html




資料庫格式與資料表:

2張資料表,books與employee
 books內容
 employee內容






conn_mysql.php:

<?php
	$db_link=@mysqli_connect("資料庫位置","資料庫帳號","資料庫密碼");
	if(!$db_link){
		die("資料庫連線失敗<br>");
	}else{
		echo"資料庫連線成功<br>";
	}
	mysqli_query($db_link,"SET NAMES 'utf-8'");  //設定字元集與編碼為utf-8
	$seldb=@mysqli_select_db($db_link,"資料庫名稱");
	if(!$seldb){
		die("資料庫選擇失敗<br>");
	}else{
		echo"資料庫選擇成功<br>";
	}
?>

login.html:

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

	</head>
	<body>
		<form method="POST" action="login_php.php">
			請輸入帳號:<input type="text" name="username"/><br>
			請輸入密碼:<input type="Password" name="password"/><br>
			<input type="submit" value="登入"/>
		</form>
	</body>
</html>

login_php.php:

<?php
	header('Content-Type: text/html; charset=utf-8');
	$username=$_POST['username'];
	$password=$_POST['password'];
	
	require("conn_mysql.php");
	$sql_query_login="SELECT * FROM employee where username='$username' AND password='$password'";
	$result1=mysqli_query($db_link,$sql_query_login) or die("查詢失敗");
	if(mysqli_num_rows($result1)){
		$sql_query="SELECT * FROM books";
		$result=mysqli_query($db_link,$sql_query);
		echo "<table border=1 width=400 cellpadding=5>";
		echo "<tr>
			<td>書籍編號</td>
			<td>書籍名稱</td>
			<td>負責員工編號</td>
			<td>價錢</td>
		      </tr>";
		while($row=mysqli_fetch_array($result)){
			
			echo "<tr>
				<td>$row[0]</td> 
				<td>$row[1]</td>
				<td>$row[2]</td>
				<td>$row[3]</td>
			      </tr>";
		
			
		}
		echo"</table>";
	}else{
		echo"登入失敗";
	}
	
	
?>

2017年8月12日 星期六

MySQL:語法


範例

資料庫名稱:test
資料表:1.books  2. employee

books結構











employee結構










books資料













employee資料













指令:

基本指令

select:SELECT指令查詢資料表時,可以指明查詢結果所需的欄位清單
select 欄位名稱 from 資料表名稱 where 條件;

distinct:在SELECT指令後可以使用DISTINCT指令分辨重複的欄位值,一旦欄位擁有重複值,就只會顯示其中一筆記錄。
SELECT DISTINCT 價錢 FROM books;

insert:在資料表插入一筆新記錄
insert into 資料表名稱 values ('值','值');

update:更新資料表的記錄,這些記錄是已經 存在的記錄
update 資料表名稱 set 欄位名稱 = '值' where 條件;

delete:刪除資料表的記錄
delete from 資料表名稱 where 條件;

as:指定中文或英文的欄位別名
SELECT 書籍名稱,價錢,價錢*0.9 AS 打折後 FROM books;

limit:可以限制傳回的資料筆數
SELECT * FROM books LIMIT 0,3;(回傳第0筆到第三筆資料)

WHERE子句 

  • 比較運算子:WHERE子句的條件可以是一個運算式,運算元是欄位 值,可以是文字、數值或日期/時間,在運算式可以使用的比較運算子, 如下表所示:

  • 邏輯運算子:WHERE子句的條件運算式可以使用邏輯運算子執行多樣化比較,或連接多 條件建立複雜的邏輯運算式,如下表所示:


is null 、 is not null:查詢資料表中指定欄位值是否為空值NULL
SELECT 書籍名稱 FROM books WHERE 書籍名稱 is NOT NULL;










and、or、not
SELECT * FROM books WHERE 價錢>=550 AND 價錢<=650;








between:在一個範圍之內
SELECT * FROM books WHERE 價錢 BETWEEN 550 AND 650;








like:%代表任何長度的任何字串;_代表一個字元長度的任何字元
SELECT * FROM books WHERE 書籍名稱 LIKE '_ava%';








In:屬於清單其中之一
SELECT * FROM books WHERE 負責員工編號 IN (1,2);









order by:指定依照欄位由小到大或由大到小進行排序。
SELECT * FROM books ORDER BY 價錢 DESC;














  • 算術運算子:WHERE子句的運算式條件可以使用算術運算子,算術運算子可以使用 SELECT指令的欄位清單,用來計算2個欄位的和, 使用各欄位組成一個算術運算式或是加上一個固 定值。



SELECT 書籍名稱,價錢,價錢*0.9 AS 打折後 FROM books;








聚合函數

  • COUNT()函數 
  • AVG()函數 
  • MAX()函數 
  • MIN()函數 
  • SUM()函數













count:計算筆數
SELECT COUNT(書籍名稱) AS 數量 FROM books;






合併查詢與子查詢

子查詢
SELECT * FROM books WHERE 負責員工編號 = (SELECT 員工編號 FROM employee WHERE 姓名 = '謝小小');









Join On:使用在多個資料表的查詢
SELECT 負責員工編號,書籍名稱,姓名 FROM employee JOIN books ON 負責員工編號 = 員工編號;










Group By :群組是以指定欄位進行分類,將欄位值中重複的值結合起
SELECT 負責員工編號,COUNT(價錢) AS 員工負責幾項 FROM books GROUP BY 負責員工編號;








Join on + Group by
SELECT 負責員工編號,COUNT(價錢),姓名 FROM books JOIN employee ON 負責員工編號 = 員工編號 GROUP BY 負責員工編號;

2017年7月29日 星期六

Android:使用JackSon函式庫解析Json

在Android裡要解析伺服端回傳的Json格式資料,除了使用內建在android studio裡的Json.org外,還可以使用第三方的函式庫,像是Gson或JackSon,JackSon是目前開放原碼中有著高效率特色的函式庫之一,常用在許多的應用程式中。


要使用JackSon解析Json資料時,需要先導入JackSon函式庫,下載網址 :
http://www.java2s.com/Code/Jar/j/Downloadjacksonall199jar.htm

下面的範例以GoogleBook的api為範例:
https://www.googleapis.com/books/v1/volumes?q=java (q後面為書名)



伺服器回傳的Json :
紅色框框為要取得的資訊title(書名)與subtitle(副標題)
PS:subTitle並不是每本書都會有
下面這本書就有subtitle了


為了好解析Json裡的資料,可以畫一張類別圖,這樣就可以知道我們接下來要準備建立哪些類別和底下有哪些屬性:

*表示多值,也就是items底下有多筆資料,像是有kind、id、etag、selfLink、volumeInfo,在Json格式裡會以[ ] 陣列表示,另外在Json格式裡{ } 表示物件



程式碼:
activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:orientation="vertical" >
    
    <TextView
        android:id="@+id/txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="書名" />
    
    <EditText 
        android:id="@+id/edt"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        />
    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="search"
        />
    
</LinearLayout>

MainActivity.java:

public class MainActivity extends Activity {
 
    private Button btn;
    private EditText edt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        findviewbyid();
        
    }
    private void findviewbyid(){
        btn = (Button)findViewById(R.id.btn);
        edt = (EditText)findViewById(R.id.edt);
        btn.setOnClickListener(btnlistener);
    }
    private View.OnClickListener btnlistener = new View.OnClickListener() {
  
  @Override
  public void onClick(View arg0) {

//   Loose Coupling
//   Intent it = new Intent("com.mchen.Activity2");
//   it.putExtra("bookName", edt.getText().toString());

     Uri uri = Uri.parse("Tom:"+edt.getText().toString());  //使用自訂的Scheme
     Intent it = new Intent(Intent.ACTION_VIEW,uri);   //跳頁到DisplayBooks
     startActivity(it);
  }
 };
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
}

BookInfo2.java:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class BookInfo2 {
 
 private int totalItems;
 private List<items> items = new ArrayList<items>();
 
 public BookInfo2(){
  
 }
 public BookInfo2(int totalItems,List<items> items){
  this.totalItems = totalItems;
  this.items = items;
 }
 
 public int getTotalItems() {
  return totalItems;
 }
 public void setTotalItems(int totalItems) {
  this.totalItems = totalItems;
 }
 public List<items> getItems() {
  return items;
 }
 public void setItems(List<items> items) {
  this.items = items;
 }
 
}

items.java:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class items {
 
 private volumeInfo volumeInfo;

 public items(){
  
 }
 
 public items(volumeInfo volumeInfo){
  this.volumeInfo = volumeInfo;
 }

 public volumeInfo getVolumeInfo() {
  return volumeInfo;
 }

 public void setVolumeInfo(volumeInfo volumeInfo) {
  this.volumeInfo = volumeInfo;
 }

}

volumeInfo.java:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class volumeInfo {
 
 private String subtitle;
 private String title;
 public String getSubtitle() {
  
  return subtitle;
  
 }
 public void setSubtitle(String subtitle) {
  this.subtitle = subtitle;
 }
 public String getTitle() {
  return title;
 }
 public void setTitle(String title) {
  this.title = title;
 }

}

book.xml:

<?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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:dividerHeight="5dp"
        android:id="@+id/listview">
    </ListView>

</LinearLayout>

row.xml:

<?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" >
    <TextView
        android:id="@+id/txtTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/txtSubTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    

</LinearLayout>

DisplayBooks.java:

public class DisplayBooks extends Activity {

 private ListView listView;

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.book);

        listView = (ListView)findViewById(R.id.listview);
        Log.i("mutin","action-"+this.getIntent().getAction());
        Log.i("mutin", "data-"+this.getIntent().getData().getSchemeSpecificPart());

        final String param = this.getIntent().getData().getSchemeSpecificPart();
        int cpuCount = Runtime.getRuntime().availableProcessors();  //取得可以建立Thread的最大數量
        ExecutorService es = Executors.newFixedThreadPool(cpuCount);   //建立Thread
        Future<String> f = es.submit(new Callable<String>(){      //可以取得Callable回傳結果

   @Override
   public String call() throws Exception {
    // TODO Auto-generated method stub
    URL url = new URL("https://www.googleapis.com/books/v1/volumes?q="+param);
    java.net.URLConnection con = url.openConnection();
    BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String data = null;
    StringBuffer result  = new StringBuffer();
    while((data=br.readLine())!=null){
     result.append(data);
    }

    return result.toString();
   }
         
        });
        try{
         String result = f.get();
         es.shutdown();

   //產生Jackson函式庫負責解析的ObjectMapper類別
         ObjectMapper mapper = new ObjectMapper();

   //呼叫ObjectMapper的readValue方法進行Json格式轉換為Java資料的工作
         BookInfo2 bi = mapper.readValue(result,BookInfo2.class);
         HashMap<String,String> map;
         ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
         for(items item:bi.getItems()){
          Log.i("mutin", "Title="+item.getVolumeInfo().getTitle());
          Log.i("mutin", "SubTitle="+item.getVolumeInfo().getSubtitle());
          
          map = new HashMap<String,String>();
                map.put("title", "Title:"+item.getVolumeInfo().getTitle());
          map.put("subTitle", "SubTitle:" + item.getVolumeInfo().getSubtitle());
                list.add(map);
         }
         
         SimpleAdapter adapter = new SimpleAdapter(this,list,R.layout.row,new String[]{"title","subTitle"},new int[]{R.id.txtTitle,R.id.txtSubTitle});
            listView.setAdapter(adapter);
         
        }catch(Exception ex){
         ex.printStackTrace();
        }
        
 }

}
PS:用HightLight上色程式碼,格式會跑掉,請見諒

執行畫面:

2017年7月25日 星期二

Android:動畫

Android目前支援3種類型的動畫:
1.影格動畫(Frame Animation)
2.補間動畫(View Animation)
3.屬性動畫(Property Animation)


(1)Frame Animation(影格動畫)類似gif動畫一樣是一連串的drawable序列組成,優點是使用簡單方便、缺點是需要事先準備好每一幀圖片。

(2)View Animation(視圖動畫)視圖動畫比較簡單,只能應用於各種View,可以做一些位置、大小、旋轉和透明度的簡單轉變。僅需定義開始與結束的關鍵幀,而變化的中間幀由系統補上,可以達到大部分的動畫需求。

(3)Property Animation(屬性動畫)是3.0後推出的動畫,優點是使用簡單、降低實現的複雜度、直接更改對象的屬性、幾乎可適用於任何對象而僅非View類,缺點是需要3.0以上的API支持


本篇介紹View Animation

可以通過xml檔定義,xml檔放於res/anim/目錄下,根項目可以為:<alpha>, <scale>, <translate>, <rotate>, 或者<set>。其中,<set>標籤定義的是動畫集,它可以包含多個其他標籤

<alpha>
可以定義動畫的透明度,也就是可以實現淡入淡出的效果
  • android:duration 動畫從開始到結束持續的時長,單位為毫秒 
  • android:fromAlpha 動畫開始時的透明度,0.0為全透明,1.0為不透明,默認為1.0 
  • android:toAlpha 動畫結束時的透明度,0.0為全透明,1.0為不透明,默認為1.0
動畫的xml檔:

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0.0"
    android:toAlpha="1.0" />
將動畫添加到view上:

view.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in));

<scale>
可以定義縮放的視圖動畫

  • android:fromXScale 表示沿X軸縮放的起始比例
  • android:toXScale 表示沿X軸縮放的結束比例
  • android:fromYScale 表示沿Y軸縮放的起始比例
  • android:toYScale 表示沿Y軸縮放的結束比例

          以上四個屬性,0.0表示縮放到沒有,1.0表示正常無縮放,小於1.0表示收縮,大於1.0表示放大

  • android:pivotX 縮放時的固定不變的X座標,一般用百分比表示,0%表示左邊緣,100%表示右邊緣
  • android:pivotY 縮放時的固定不變的Y座標,一般用百分比表示,0%表示頂部邊緣,100%表示底部邊緣

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:pivotX="0%"
    android:pivotY="100%"
    android:toXScale="1.5"
    android:toYScale="1.5" />

<translate>
可以定義位移的動畫效果

  • android:interpolator 表示動畫加速器,可設定屬性有accelerate_interpolator(加速)、decelerate_interpolator(減速)和accelerate_decelerate_interpolator(加速減速)
  • android:fromXDelta 動畫起始位置的水平坐標
  • android:toXDelta 動畫結束位置的水平坐標
  • android:fromYDelta 動畫起始位置的垂直坐標
  • android:toYDelta 動畫結束位置的垂直坐標
  • android:duration 動畫的持續時間,單位是毫秒

座標的值可以有三種格式:從-100到100;以"%"結束,表示相對於View本身的百分比位置;如果以"%p"結束,表示相對于View的父View的百分比位置;如果沒有任何尾碼,表示相對於View本身具體的圖元值。

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fromXDelta="-100%"
    android:fromYDelta="0"
    android:toXDelta="100%p"
    android:toYDelta="0" />

<rotate>
可以定義旋轉的動畫

  • android:fromDegrees 表示旋轉的起始角度
  • android:toDegrees 表示旋轉的結束角度
  • android:repeatCount 設定旋轉的次數,0表示不重複,1表示會多旋轉一次,infinite或-1表示一直旋轉
  • android:repeatMode 設定重複的模式,有restart與reverse,預設是restart,該屬性只有當repeatCount設定大於0或infinite時才有作用

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%" />

<set>
可以將多個動畫組合成一個動畫集

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate 
        android:fromYDelta="100%p" 
        android:toYDelta="0"
        android:duration="2000"/>
    <alpha 
        android:fromAlpha="0.0" 
        android:toAlpha="1.0"
        android:duration="2000" />
</set>

2017年7月18日 星期二

Android:Fragment(片段)

當還沒有Fragment功能出來以前,必須使用很多個Activity來轉換到另一個Activity的方式來設計功能,這在手機上使用來看,感覺起來沒什麼問題,但是平板出來之後,畫面變大,一個畫面可以容納更多的元件,所以為了讓Android UI在平板上可以有更好的展示效果,Android在3.0時加入了Fragment功能。



Fragment片段是Android提供的一個畫面區塊,可以將Fragment放在一個Activity中,Fragment可以說是Activity的子畫面。

開發上使用Fragment的好處是:

  • 有自己的生命週期
  • 可以重複利用降低開發成本
  • 一個Fragment在手機和平板上可以有不同的使用者體驗


Fragment與Activity的生命週期:


Fragment的生命週期必須依附Activity的生命週期,意思是說,當 Activity 暫停時,其中的所有片段也會一併暫停;而當 Activity 遭到刪除時,所有片段也會一併刪除。 不過,當 Activity 執行時 (該 Activity 會處於繼續進行生命週期狀態),您可以個別操縱所有片段,例如新增或移除片段。

Fragment動態佈署主要分為動態新增(add)動態置換(replace兩種:

  • replace是每次呼叫,不管有沒有建立過fragment,都會創建一個新的Fragment,所以生命週期也會重跑一遍,如果使用在需要經常更換fragment的時候,非常消耗資源。
  • add則是可以搭配hide()與show()來建立Fragment,當要切換Fragment時,可以hide()當前的fragment,並且add()和show()新的fragment


動態置換(replace)程式碼:

activity_main.xml:

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

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="20dp" />

    <RadioGroup
        android:id="@+id/id_radioGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/id_one"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page1"
            android:onClick="onClick"/>


        <RadioButton
            android:id="@+id/id_two"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page2"
            android:onClick="onClick"/>

        <RadioButton
            android:id="@+id/id_three"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page3"
            android:onClick="onClick"/>

        <RadioButton
            android:id="@+id/id_four"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page4"
            android:onClick="onClick"/>

    </RadioGroup>
</RelativeLayout>


MainActivity.java:

public class MainActivity extends FragmentActivity {
    private RadioButton id_one,id_two,id_three,id_four;
    private int page = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        findviewbyid();
        changeFragment(DetailsFragment.newInstance(page));

    }
    public void onClick(View view){
        switch (view.getId()){
            case R.id.id_one:
                changeFragment(DetailsFragment.newInstance(1));
                break;
            case R.id.id_two:
                changeFragment(DetailsFragment.newInstance(2));
                break;
            case R.id.id_three:
                changeFragment(DetailsFragment.newInstance(3));
                break;
            case R.id.id_four:
                changeFragment(DetailsFragment.newInstance(4));
                break;
        }
    }
    private void findviewbyid(){
        id_one = (RadioButton)findViewById(R.id.id_one);
        id_two = (RadioButton)findViewById(R.id.id_two);
        id_three = (RadioButton)findViewById(R.id.id_three);
        id_four = (RadioButton)findViewById(R.id.id_four);
    }

    private void changeFragment(Fragment f) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_container, f);
        transaction.commitAllowingStateLoss();
    }
    protected void onStart(){
        super.onStart();
        Log.i("tag","Activity onStart()");
    }
    protected void onResume(){
        super.onResume();
        Log.i("tag","Activity onResume()");
    }
}

fragment_tmp.xml(fragment內容的佈局文件):

<?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:gravity="center"
    android:orientation="vertical" >

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/text_view"
            android:text="fragment"
            android:gravity="center"
            android:textSize="20sp"/>

</LinearLayout>

DetailFragment.java:

public class DetailsFragment extends Fragment {


    private View v;
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.i("tag","Fragment onCreateView()");
        v = inflater.inflate(R.layout.fragment_tmp, container, false);
        TextView text = (TextView)v.findViewById(R.id.text_view);
        text.setText("Page" + getShownIndex());
        return v;
    }


}

執行結果:


動態新增(add)程式碼:

activity_main.xml :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="20dp" />

    <RadioGroup
        android:id="@+id/id_radioGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/id_one"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page1"
            android:onClick="onClick"/>


        <RadioButton
            android:id="@+id/id_two"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page2"
            android:onClick="onClick"/>

    </RadioGroup>
</RelativeLayout>

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private RadioButton id_one,id_two;
    private Fragment1 mFragment01;
    private Fragment2 mFragment02;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findviewbyid();
        mFragment01 = new Fragment1();
        mFragment02 = new Fragment2();
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_container, mFragment01,"TAG-mFragment01");
        transaction.commitAllowingStateLoss();

    }

    private void findviewbyid(){
        id_one = (RadioButton)findViewById(R.id.id_one);
        id_two = (RadioButton)findViewById(R.id.id_two);
    }
    public void onClick(View view){
        switch (view.getId()){
            case R.id.id_one:
                chaangefragment(mFragment01,"TAG-mFragment01");
                break;
            case R.id.id_two:
                chaangefragment(mFragment02,"TAG-mFragment02");
                break;
        }
    }
    public void chaangefragment(Fragment fragment,String tag){
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
        List fragments = fragmentManager.getFragments();
        Fragment tmp=null;
        for (Fragment f: fragments){
            if (f!=null && f.isVisible()) {
                System.out.println("hide"+f.getTag());
                tmp=f;
            }
        }
//        Fragment fragment = getSupportFragmentManager().findFragmentByTag("TAG-mFragment01");
//        System.out.println(fragment);
        if (fragment.isAdded()){
            transaction.hide(tmp).show(fragment).commit();
        }else {
            transaction.hide(tmp).add(R.id.fragment_container,fragment,tag).commit();
        }
    }
}

fragment_layout.xml:

<?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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txt"
        android:text="fragment"/>

</LinearLayout>

fragment1.java:

public class Fragment1 extends Fragment {

    private TextView txt;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.i("tag","Fragment1  onCreateView");
        return inflater.inflate(R.layout.fragment_layout, container, false);

    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.i("tag","Fragment1  onActivityCreated");
        txt = (TextView)getView().findViewById(R.id.txt);
        txt.setText("fragment1");
    }


    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.i("tag","Fragment1  onAttach");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("tag","Fragment1  onCreate");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.i("tag","Fragment1  onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.i("tag","Fragment1  onResume");
    }
}

fragment2.java:

public class Fragment2 extends Fragment{

    private TextView txt;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.i("tag","Fragment2  onCreateView");
        return inflater.inflate(R.layout.fragment_layout, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.i("tag","Fragment2  onActivityCreated");
        txt = (TextView)getView().findViewById(R.id.txt);
        txt.setText("fragment2");
    }
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.i("tag","Fragment2  onAttach");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("tag","Fragment2  onCreate");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.i("tag","Fragment2  onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.i("tag","Fragment2  onResume");
    }
}

執行順續page1(起始) -> page2 -> page1 -> page2
執行結果:

可以看到fragment1和fragment2個別被建立1次後,之後再呼叫時就不會再被建立新的Fragment了。