2015年7月30日 星期四

Android 實作 自定義對話框樣式 類似Line 提示對話框 Custom Dialog

最近需要實作類似Line的訊息通知視窗

如下圖所示




目前想的一些限制是

1.能自定義樣式
2.背景必須半透明
3.能夠在APP在背景執行時  直接彈出顯示

我們先建立一個 MainActivity 建置兩個按鈕

第一個按鈕是按下直接跳出 對話框
第二個按鈕是按下之後 五秒跳出對話框
 
如下圖


MainActivity.java

package com.example.ellis_wu.customdialogdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;


public class MainActivity extends Activity {

    private Button btn_open;
    private Button btn_delay_open;

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

        btn_open = (Button)findViewById(R.id.btn_open);
        btn_delay_open = (Button)findViewById(R.id.btn_delay_open);

        btn_open.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,CustomDialogActivity.class);
                startActivity(intent);
            }
        });

        btn_delay_open.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,CustomDialogActivity.class);
                try {
                    Thread.sleep(5000);
                    startActivity(intent);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

自訂對話框樣式的部分我們希望的樣式為


 
因此先建置對話框的 layout

activity_custom_dialog.xml
 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:transitionGroup="false"
    android:nestedScrollingEnabled="false"
    tools:context="com.example.ellis_wu.customdialogdemo.CustomDialogActivity"
    android:id="@+id/dialogBackground"
    android:gravity="center_vertical|center_horizontal">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="330dp"
        android:layout_height="270dp"
        android:background="#ffffffff">
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="60dp"
            android:layout_margin="0dp"
            android:focusable="true"
            android:background="#ffff3826">

            <Button
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="X"
                android:id="@+id/text_close"
                android:layout_gravity="right"
                android:layout_alignParentRight="true"
                android:background="#00ffffff"
                android:textColor="@android:color/white"
                android:layout_centerVertical="true"
                android:layout_margin="5dp"
                android:padding="5dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:id="@+id/text_title"
                android:text="客製化視窗"
                android:minHeight="50dp"
                android:padding="10dp"
                android:textColor="@android:color/white"
                android:layout_alignParentLeft="true"
                android:layout_margin="5dp" />
        </RelativeLayout>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:id="@+id/text_content"
            android:text="這是您客製化的視窗!"
            android:textColor="@android:color/black"
            android:minHeight="100dp"
            android:padding="30dp"
            android:background="@android:color/white"
            android:gravity="center_vertical" />

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:weightSum="1">
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="確認"
                android:id="@+id/btn_confirm"
                android:layout_gravity="center_horizontal"
                android:layout_weight="0.21" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="取消"
                android:id="@+id/btn_cancel"
                android:layout_gravity="center_horizontal"
                android:layout_weight="0.22" />
        </LinearLayout>

    </LinearLayout>

</LinearLayout>
 
 

我們為客製化的對話框建立一個Activity

CustomDialogActivity.java

public class CustomDialogActivity extends Activity {
    Button btn_confirm;
    Button btn_cancel;
    TextView text_content;
    TextView text_title;
    TextView text_close;
    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_dialog);

        btn_confirm = (Button)findViewById(R.id.btn_confirm);
        btn_cancel = (Button)findViewById(R.id.btn_cancel);
        text_close = (TextView)findViewById(R.id.text_close);
        text_title  = (TextView)findViewById(R.id.text_title);
        text_content = (TextView)findViewById(R.id.text_content);

        btn_confirm.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Toast.makeText(CustomDialogActivity.this,"you click confirm!",Toast.LENGTH_SHORT).show();
                finish();
            }
        });
        btn_cancel.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Toast.makeText(CustomDialogActivity.this,"you click cancel!",Toast.LENGTH_SHORT).show();
                finish();
            }
        });
        text_close.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Toast.makeText(CustomDialogActivity.this,"you click close!",Toast.LENGTH_SHORT).show();
                finish();
            }
        });
    }
}


執行程式結果畫面:
1.發覺背景沒有半透明



為了解決背景半透明 在 AndroidManifest.xml 中 CustomDialogActivity
設定 theme為

    android:theme="@android:style/Theme.Dialog"
 
 
執行程式結果畫面
背景半透明成功
不過客製化視窗上方多了一段黑色區域


 
原來黑色區域是本來Dialog的Title部分
在 CustomDialogActivity 中加入
 
requestWindowFeature(Window.FEATURE_NO_TITLE);

重新執行程式:
黑色區域消失




接下來要測試 是否能夠在App在背景執行的時候 能夠彈出視窗
按下第二顆按鈕後 按下Home 鍵回到桌面
讓App不再顯示在前景

執行結果發覺 無法顯示客製化視窗

解決方案:
在AndroidManifest.xml 中
設定 MainActivity 的launchMode 為 singleInstance

android:launchMode="singleInstance"
 
注意:此設定會讓MainActivity 即使被重複呼叫 也只會有一個instance 
即便是 跨 application 也是都會重用這個 Activity instance

再執行一次程式

可成功在桌面時顯示客製化的視窗
 
  

此時按下Home鍵右方的 recent app 按鈕

發覺在 recent app list 中 
CustomDialogActivity 取代了本來的 MainActivity 
並且就算按下關閉 也不會在 recent app 中消失



這不是我想要的效果

因此在AndroidManifest.xml 中 加入設定

android:noHistory="true" 
android:taskAffinity="" 
android:excludeFromRecents="true"
 
讓CustomDialogActivity 不要出現在 recent app list 中

執行結果 



CustomDialogActivity不會覆蓋 MainActivity

並且之後會自動消失在 recent app list  中

最後附上完成的檔案 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ellis_wu.customdialogdemo" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:launchMode="singleInstance"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".CustomDialogActivity"
            android:label="@string/title_activity_custom_dialog"
            android:noHistory="true"
            android:taskAffinity=""
            android:excludeFromRecents="true"
            android:theme="@android:style/Theme.Dialog">
        </activity>
    </application>

</manifest>



CustomDialogActivity 檔
 
public class CustomDialogActivity extends Activity {
    Button btn_confirm;
    Button btn_cancel;
    TextView text_content;
    TextView text_title;
    TextView text_close;
    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_custom_dialog);

        btn_confirm = (Button)findViewById(R.id.btn_confirm);
        btn_cancel = (Button)findViewById(R.id.btn_cancel);
        text_close = (TextView)findViewById(R.id.text_close);
        text_title  = (TextView)findViewById(R.id.text_title);
        text_content = (TextView)findViewById(R.id.text_content);

        btn_confirm.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Toast.makeText(CustomDialogActivity.this,"you click confirm!",Toast.LENGTH_SHORT).show();
                finish();
            }
        });
        btn_cancel.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Toast.makeText(CustomDialogActivity.this,"you click cancel!",Toast.LENGTH_SHORT).show();
                finish();
            }
        });
        text_close.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                Toast.makeText(CustomDialogActivity.this,"you click close!",Toast.LENGTH_SHORT).show();
                finish();
            }
        });
    }
}


參考資料:

1.讓Activity不要出現在recent App list
https://stackoverflow.com/questions/18301774/removing-activity-from-recent-apps-keeping-older-one/22126453#22126453


2.使用Activity 的方式客製化視窗
http://www.javabeat.net/dialog-activity-android/


3.Activity launchMode 詳細說明
http://blog.csdn.net/zhangjg_blog/article/details/10923643
 

沒有留言:

張貼留言