常常用到實作Java API已寫好的界面,可是都從沒實際設計界面含傾聽事件,現在就來說要如何弄出可時時發送資料的界面,讓其他類監聽,取得資料
下面程式是大致的流程,interface_A類,設計界面data_change_lister被監聽類實作,含有一方法void capture_data_change(int data)要被監聽類實作的方法,其中data是我們要被其他監聽類,監聽的資料,void set_data_change_lister(data_change_lister lister)這個可指定其他監聽類來傾聽
,透過mlister.capture_data_change(i)來發送資料.
當然要達到像下面不同類傳送資料,不用界面也可,但都要在類內實例化其他監聽類,在送出資料,程式碼顯得很亂,透過界面不須實例化監聽類,界面類根本不需要考慮是任何類來監聽資料,變得有規律,透過界面更為周詳,更有彈性,譬如在遊戲中做幾拾個甚至幾百個物體碰撞判別,之前文章python gtk cairo射擊小遊戲,也有類似方法,不過有些時間忘了是如何實現的,要回去看程式碼才知道.
簡單說java 的界面類,不需實例化監聽類,只需指定界面變數,透過界面實例化該監聽類成員,不需要管監聽成員的類別,若不用界面也可以,但實例化必須是該監聽類,才能對該監聽類發送資料,以前我都是用後者來發送.
注意下面紅色粗體字mlister是界面變數,但在set_data_change_lister,卻是可以指定任何類成為這個界面變數,原因在監聽類implements後就可變成該界面型態,而被當引數指成改界面變數mlister,呼叫本身的實作方法mlister.capture_data_change(i),就可取得該i資料了,若界面類是一個Thread,將傳送資料放在run()方法中while(){傳送資料},start()後可持續監聽該資料
主Class 監聽類B:
Class B宣告實作interface_A.data_change_lister,實例化interface_A,加入事件傾聽者minterface_A.set_data_change_lister(this)
實作capture_data_change(int data)監聽了data,start thread結果會在terminal印出0 1 2 3 4 5 6 7 8 9
//Class B宣告實作interface_A.data_change_lister
public class B implements interface_A.data_change_lister{
public B(){
//實例化interface_A
interface_A minterface_A=new interface_A();
//加入事件傾聽者
minterface_A.set_data_change_lister(this);
//start thread
minterface_Aminterface_A.start()
}
@Override
public void capture_data_change(int data){
//時時傾聽data變化
Log.d("TAG_DATA","Data change: "+data);
}
}
界面類interface_A:注意這裡沒實例化CLass B,是透過界面來實例化任何監聽類
//Class interface_A設計界面data_change_lister
public class interface_A extends Thread{
//這裡指定界面變數,用來接受監聽類成員
private data_change_lister mlister;
//建構子
public interface_A(){..........}
@Overrid
public void run(){
//舉例傳送0 1 2 3 4 5 6 7 8 9資料
if(mlister!=null)
{
//透過介面mlister變數給事件傾聽者傳送資料
for(int i=0;i < 10;i++){
mlister.capture_data_change(i);
}
}
}
//關鍵在這界面變數,可以設定是任何類,設定mlister變數成為其他監聽類實例化
public void set_data_change_lister(data_change_lister lister){
mlister=lister;
Log.d("TAG_DATA","set listener "+mlister);
}
//設計data_change_lister界面
public interface data_change_lister{
//資料變化時,捕捉資料data
void capture_data_change(int data);
}
}
read more...
2017年4月30日 星期日
2017年4月29日 星期六
讓Class View跟一般class Thread一模一樣
如何讓Class View跟一般class Thread一模一樣,當要使用Canvas一定要繼承View才能作畫,就沒法繼承Thread,因為java只能單一繼承
若要View能有Thead功能,只能實作Runnable,但是class實作Runnable是沒有像Thread有start()函式,那要test_vew開始執行續要這樣,
要如下面這要,每次都要new Thread,我覺的這樣太麻煩
//實例化test_view
test_view mtest_view=new test_view(.....);
//mtest_view新的Thread才能start(),
new Thread(mtest_view).start();
Example 1:
public class test_view extends View implements Runnable{
@Override
public void run(){
while(true){
this.update();//update view產生動畫
}
}
@Override
protected void onDraw(Canvas canvas) {
//處理canvas
}
}
我想到一個方法,在test_view 加一個start()函式,寫入new Thread(this).start(),那要test_vew開始執行續就跟Class Thread一模一樣
//實例化test_view
test_view mtest_view=new test_view(.....);
//開始Thread
mtest_view.start();
Example 2:
public class test_view extends View implements Runnable{
public void start(){
new Thread(this).start();
}
@Override
public void run(){
while(true){
this.update();//update view產生動畫
}
}
@Override
protected void onDraw(Canvas canvas) {
//處理canvas
}
}
若要實例化就開始Thread,建構子加入this.start(),這樣在實例化就會開始Thread了
//實例化test_view且開始Thread
test_view mtest_view=new test_view(.....);
Example 3:
public class test_view extends View implements Runnable{
public test_view(Context t){
super(t)
this.start();
}
public void start(){
new Thread(this).start();
}
@Override
public void run(){
while(true){
this.update();//update view產生動畫
}
}
@Override
protected void onDraw(Canvas canvas) {
//處理canvas
}
}
這樣extends View implements Runnable對用view來作動畫或遊戲就很方便,一個view就是一個Thread,每各View就有個別的生命,可產生不同行為
read more...
若要View能有Thead功能,只能實作Runnable,但是class實作Runnable是沒有像Thread有start()函式,那要test_vew開始執行續要這樣,
要如下面這要,每次都要new Thread,我覺的這樣太麻煩
//實例化test_view
test_view mtest_view=new test_view(.....);
//mtest_view新的Thread才能start(),
new Thread(mtest_view).start();
Example 1:
public class test_view extends View implements Runnable{
@Override
public void run(){
while(true){
this.update();//update view產生動畫
}
}
@Override
protected void onDraw(Canvas canvas) {
//處理canvas
}
}
我想到一個方法,在test_view 加一個start()函式,寫入new Thread(this).start(),那要test_vew開始執行續就跟Class Thread一模一樣
//實例化test_view
test_view mtest_view=new test_view(.....);
//開始Thread
mtest_view.start();
Example 2:
public class test_view extends View implements Runnable{
public void start(){
new Thread(this).start();
}
@Override
public void run(){
while(true){
this.update();//update view產生動畫
}
}
@Override
protected void onDraw(Canvas canvas) {
//處理canvas
}
}
若要實例化就開始Thread,建構子加入this.start(),這樣在實例化就會開始Thread了
//實例化test_view且開始Thread
test_view mtest_view=new test_view(.....);
Example 3:
public class test_view extends View implements Runnable{
public test_view(Context t){
super(t)
this.start();
}
public void start(){
new Thread(this).start();
}
@Override
public void run(){
while(true){
this.update();//update view產生動畫
}
}
@Override
protected void onDraw(Canvas canvas) {
//處理canvas
}
}
這樣extends View implements Runnable對用view來作動畫或遊戲就很方便,一個view就是一個Thread,每各View就有個別的生命,可產生不同行為
read more...
2017年4月28日 星期五
Android音頻可視化用Visualizer這個API輕鬆實現
Android音頻可視化,可以用Visualizer這個API輕鬆實現,上面影片,啟動6個Thread取得主Class音頻輸出流作動畫Update,
其實簡單方法的不須用Thread,使用監聽方法onWaveFormDataCapture或onFftDataCapture中去update動畫既可
1.宣告實作implements Visualizer.OnDataCaptureListener界面
2.實作OnDataCaptureListener界面的2個method
@Override
public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
//取得音頻輸出流,給Canvas作後續處理
mwaveform=waveform;
}
@Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
}
3.設定監聽實作界面的2個method,取得音頻輸出流
//實例化 Visualizer ,0指Audio output
audioOutput = new Visualizer(0);
//加入傾聽事件,時時監聽實作界面的2個method,便可從實作界面的2個method時時取得音頻輸出流
audioOutput.setDataCaptureListener(this,Visualizer.getMaxCaptureRate(),true,false);
4.對音頻輸出流作可視化處理,運算完用Canvas在View Class繪出圖形,google一下有運算公式
把一些不相干的去掉,代碼簡化,比較看得懂
public class MainActivity extends AppCompatActivity implements Visualizer.OnDataCaptureListener{
private Visualizer audioOutput = null;
private byte[] mwaveform=null;
...................................................
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//實例化 Visualizer ,0指Audio output
audioOutput = new Visualizer(0); // get output audio stream
//第2參數true指onWaveFormDataCapture() run第3參數false指onFftDataCapture no run
audioOutput.setDataCaptureListener(this,Visualizer.getMaxCaptureRate(),true,false);
start_Visualizer();
..................................................
}
@Override
protected void onDestroy() {
super.onDestroy();
stop_Visualizer();
//釋放Visualizer
audioOutput.release();
}
/////////////////////////////////////實作OnDataCaptureListener 1////////////////////////////////////
@Override
public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
//Log.d("TAG","LENGTH"+waveform.length);
//print byte waveform[0]=-128~128 waveform[1]=-128~128 ....................
//可將 waveform[0]... 放入List,再根據List用Canvas畫出來
//取得音頻輸出流,作後續處理
mwaveform=waveform;
}
////////////////////////////////////////實作OnDataCaptureListener 2////////////////////////////////////
@Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//開始Visualizer
private void star_Visualizert(){
audioOutput.setEnabled(true);
}
//停止Visualizer
private void stop_Visualizer() {
audioOutput.setEnabled(false);
}
//CLASS取得音頻輸出流 method,給Class View Canvas作後續處理
public byte[] get_waveform_value(){
return mwaveform;
}
}
read more...
2017年4月18日 星期二
MediaProjection MediaCodec解碼器聲音加影像全螢幕錄屏
htc e9+plus
htc derise 820( 錄影加截圖)
影片是錄製結果,聲音是透過麥克風會有一些雜音,效果還可以比MediaRecorder好很多
剛開始htc e9+跑很OK,換到htc derise 820 MediaMuxer.stop()會崩貴,和presentationTimeUs error 錄製就中斷,弄好幾天,終於解掉錯誤正常了
剛開始htc e9+跑很OK,換到htc derise 820 MediaMuxer.stop()會崩貴,和presentationTimeUs error 錄製就中斷,弄好幾天,終於解掉錯誤正常了
MediaCodec解碼器流程
會寫程式,應該都知道解碼器一定必須要用執行緒Thread去跑
public void run()
{
//解碼器
while(true){………}
}
1.
使用者授權取得mMediaProjection後
2.
MediaCodec定義格式preparerecorder取得surface,建立VirtualDisplay
3解碼器流程
while (!mQuit.get()) {
//根據MediaCodec,dequeueOutputBuffer() 傳回整數值
int index = mMediaCodec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
//後續輸出格式產生變化,譬如放音樂,暫停音樂,
if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
//重設格式resoutputform
at
} else
//INFO_TRY_AGAIN_LATER指請求超時
if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
等待一下sleep
} else
//大於0有效輸出
if (index >= 0) {
開始解碼encode
mMediaCodec.releaseOutputBuffer(index, false);//釋放輸出buffer
mMediaCodec.releaseOutputBuffer(index, false);//釋放輸出buffer
}
}
release();//最後一定要釋放掉,否則格式會錯
}
從暫存器MediaCodec.dequeueOutputBuffer()會傳回整數值,去判斷資料內容,會有三種狀況,當一組buffer處理完就要釋放releaseOutputBuffer(index, false),在處理下 一組
A.整數值MediaCodec.INFO_OUTPUT_FORMAT_CHANGED代表輸出格式產生變化
B.整數值MediaCodec.INFO_TRY_AGAIN_LATER代表請求超時
C.整數值大於等於0代表有效輸出
處理A狀況:
需要重設MediaCodec,使用getOutputFormat()重設,此使就可addTrack給MediaMuxer後續做寫入動作
MediaFormat newFormat = mMediaCodec.getOutputFormat(); mVideoTrackIndex = mMediaMuxer.addTrack(newFormat);
MediaFormat newFormat = mMediaCodec.getOutputFormat(); mVideoTrackIndex = mMediaMuxer.addTrack(newFormat);
mMediaMuxer.start();
處理B狀況:
等待一下sleep就可
處理C狀況:
把整數值餵給解碼器,開始解碼
為什會發生A狀況輸出格式產生變化,舉個例當解碼時使用者暫停或播放音樂,輸出格式就會產生變化
輸出格式產生變化,為什要重設格式,輸出格式產生變化getOutputFormat()會不一樣,
若不getOutputFormat()加入MediaMuxer add track,資料是寫不進去的,會產生error
4.至於後續解碼器根據索引值index整數值,取得buffer dat,這裡沒列出來,這部分較複雜,網路上有例子,影像解碼器比較單純只處理OUTPUT端,INPUT端 已交給VirtualDisplay,會些程式的,應該都看得懂,聲音解碼器須用另一個Thread去repeat流程
MediaCodec原理
1.
MediaCodec有一輸出端和輸入輸入端共用一組Buffer
2.
repeat流程
開始先準備給輸入端的buffer data,也就是採樣,譬如從麥克風或SPEAKER採樣
準備好輸入端buffer data,就開始第一次buffer data丟給MediaCodec,首先向MediaCodec申請一組空的buffer,把準備好輸入端buffer data添進申請的buffer,再把buffer送回MediaCodec, MediaCodec就會處理,然後MediaCodec處理資料添進這buffer送到輸出端,使用者拿到buffeer data,處理完資料,再把這組buffer送回MediaCodec然後release,這樣就完成一回INPUT和OUTPUT,只要一直重複這動作,這裡只介紹解碼流程
MediaCodec根據機器不同,會有不同狀況發生,A手機跑沒問題,B手機可能有問題,就要解BUG
解碼器流程關鍵代碼
MediaCodec原理
1.
MediaCodec有一輸出端和輸入輸入端共用一組Buffer
2.
repeat流程
開始先準備給輸入端的buffer data,也就是採樣,譬如從麥克風或SPEAKER採樣
準備好輸入端buffer data,就開始第一次buffer data丟給MediaCodec,首先向MediaCodec申請一組空的buffer,把準備好輸入端buffer data添進申請的buffer,再把buffer送回MediaCodec, MediaCodec就會處理,然後MediaCodec處理資料添進這buffer送到輸出端,使用者拿到buffeer data,處理完資料,再把這組buffer送回MediaCodec然後release,這樣就完成一回INPUT和OUTPUT,只要一直重複這動作,這裡只介紹解碼流程
MediaCodec根據機器不同,會有不同狀況發生,A手機跑沒問題,B手機可能有問題,就要解BUG
解碼器流程關鍵代碼
public class surface_mediacodec extends Thread {
………………………….
@Override
public void run()
{
startRecord();//開始錄屏
}
public void startRecord() {
preparerecorder();
//設置MediaCodec video
//preapareaudioencoder();
//設置MediaCodec audio
vp = mp.createVirtualDisplay("record_screen", mwindowWidth, mwindowHeight, mscreendi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mSurface, null, null);
//開始錄製
recorder_VirtualDisplay();
}
private void recorder_VirtualDisplay() {
//根據根據MediaCodec,dequeueOutputBuffer() 傳回整數值
while (!mQuit.get()) {
int index = mMediaCodec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
//INFO_OUTPUT_FORMAT_CHANGED指後續輸出格式產生變化,譬如放音樂,暫停音樂,
// 呼叫resetOutputFormat()會同時啟動音頻audio_encoder Thread解碼
// 若audio_encoder thread已不在會重新建立,譬如暫停音樂,音源解完,audio_encoder會等於null //若再啟動音樂,又會重新建立新的audio_encoder Thread
if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { resetOutputFormat();//重設格式,啟動MediaMuxer
} else
//INFO_TRY_AGAIN_LATER指請求超時,等待一下
if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
try {
Thread.sleep(time_out_sleep);
Log.d("TAG","time delay");
} catch (InterruptedException e) {
e.printStackTrace();
}
} else
//大於0有效輸出,開始解碼
if (index >= 0) {
if (!MUXER_START) {
throw new IllegalStateException("MediaMuxer do not call addTrack(format)");
}
encodecToVideoTrack(index);
mMediaCodec.releaseOutputBuffer(index, false);//釋放輸出buffer }
}
release();//最後一定要釋放掉,否則格式會錯
}
//影像解碼器
private void encodecToVideoTrack(int index) {
………………
}
//重設格式
private void resetOutputFormat() {
//產生Thread音源解碼器,處理音源,並啟動,第一次是null會被建立
if(maudio_encoder==null){
maudio_encoder=new audio_encoder(TIMEOUT_US,time_out_sleep,this);
maudio_encoder.start();
}
//若Thread存在,resetOutputFormat
if(maudio_encoder!=null){
maudio_encoder.resetOutputFormat();
}
//vedio resetOutputFormat
MediaFormat newFormat = mMediaCodec.getOutputFormat();
//MediaMuxer add Track
mVideoTrackIndex = mMediaMuxer.addTrack(newFormat);
//啟動MediaMuxer
mMediaMuxer.start();
……………
}
private void release(){
……………………
}
@Override
public void run()
{
startRecord();//開始錄屏
}
public void startRecord() {
preparerecorder();
//設置MediaCodec video
//preapareaudioencoder();
//設置MediaCodec audio
vp = mp.createVirtualDisplay("record_screen", mwindowWidth, mwindowHeight, mscreendi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mSurface, null, null);
//開始錄製
recorder_VirtualDisplay();
}
private void recorder_VirtualDisplay() {
//根據根據MediaCodec,dequeueOutputBuffer() 傳回整數值
while (!mQuit.get()) {
int index = mMediaCodec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
//INFO_OUTPUT_FORMAT_CHANGED指後續輸出格式產生變化,譬如放音樂,暫停音樂,
// 呼叫resetOutputFormat()會同時啟動音頻audio_encoder Thread解碼
// 若audio_encoder thread已不在會重新建立,譬如暫停音樂,音源解完,audio_encoder會等於null //若再啟動音樂,又會重新建立新的audio_encoder Thread
if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { resetOutputFormat();//重設格式,啟動MediaMuxer
} else
//INFO_TRY_AGAIN_LATER指請求超時,等待一下
if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
try {
Thread.sleep(time_out_sleep);
Log.d("TAG","time delay");
} catch (InterruptedException e) {
e.printStackTrace();
}
} else
//大於0有效輸出,開始解碼
if (index >= 0) {
if (!MUXER_START) {
throw new IllegalStateException("MediaMuxer do not call addTrack(format)");
}
encodecToVideoTrack(index);
mMediaCodec.releaseOutputBuffer(index, false);//釋放輸出buffer }
}
release();//最後一定要釋放掉,否則格式會錯
}
//影像解碼器
private void encodecToVideoTrack(int index) {
………………
}
//重設格式
private void resetOutputFormat() {
//產生Thread音源解碼器,處理音源,並啟動,第一次是null會被建立
if(maudio_encoder==null){
maudio_encoder=new audio_encoder(TIMEOUT_US,time_out_sleep,this);
maudio_encoder.start();
}
//若Thread存在,resetOutputFormat
if(maudio_encoder!=null){
maudio_encoder.resetOutputFormat();
}
//vedio resetOutputFormat
MediaFormat newFormat = mMediaCodec.getOutputFormat();
//MediaMuxer add Track
mVideoTrackIndex = mMediaMuxer.addTrack(newFormat);
//啟動MediaMuxer
mMediaMuxer.start();
……………
}
private void release(){
……………………
}
read more...
2017年4月10日 星期一
Android studio 建立Tabbed Activity
上面影片就是Tabbed Activity效果,準備弄個漂亮的介面來寫擷取和錄製Screen的APP
A.
android studio新增Tabbed Activity
B.
public boolean onCreateOptionsMenu(Menu menu)這個methoid 會產生menu表單
要新增menu item在在menu目錄下menu_main.xml來新增(如下圖)
public boolean onOptionsItemSelected(MenuItem item) 處理選單事件
C.
mViewPager.addOnPageChangeListener(...)這是額外加上,處理ViewPaber更改頁面事件,譬如來更改toolbar的title,icon
D.
Fragment:
public View onCreateView(....)這裡來更改ViewPager裡面的原件或內容,
不要用getArguments().getInt(ARG_SECTION_NUMBER)去判斷目前viewPager當前的頁面E.
FragmentPagerAdapter:
public int getCount() 設定幾個頁面
F.menu icon不顯示(google上找到)把MenuBuilder的setOptionalIconsVisible設為true就能顯示icon
values目錄下有styles.xml,string.xml,color.xml,dimens.xml
styles.xml自訂theme
color.xml自訂color對應styles.xml
string.xml自訂的文字
dimens.xml自訂的dimens
icon圖片放在drawable
package com.example.yplin.screenrecorder; //res-value-styles.xml自訂style對應color.xml
//可將icon png複製到res-drawable,只能使用小寫會底線命名
//appbar的layout_behavior必須添加屬性@string/appbar_scrolling_view_behavior,不被攔截
//toolbar的layout_scroollFlags將scrool取消讓toolbar不能滑動
//增加menu item這裡加入選項,res-menu-menu_main.xml
//讓Icon 顯示,把MenuBuilder的setOptionalIconsVisible設為true就能顯示icon
import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.view.menu.MenuBuilder; import android.support.v7.widget.Toolbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.Button; import android.widget.RelativeLayout; import android.widget.TextView; import java.lang.reflect.Method; public class MainActivity extends AppCompatActivity { /**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
private SectionsPagerAdapter mSectionsPagerAdapter; /**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager; private static int mpage=0;//一開始第0頁
private String recorder_text="左右滑動來選擇錄製或截圖"; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); // Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container); mViewPager.setAdapter(mSectionsPagerAdapter);
toolbar.setTitle("全螢幕截圖"); toolbar.setLogo(R.drawable.image_recorder); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);//add a button
fab.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View view) { //listener
//由下而上滑動
Snackbar.make(view, recorder_text, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); //這裡放截圖事件 } }); //我們用addOnPageChangeListeneraddOnPageChangeListener來取得當前page
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { Log.d("TAG","position:"+position); switch(position){ case 0: toolbar.setTitle("截屏錄屏服務"); toolbar.setLogo(R.drawable.image_recorder); recorder_text="左右滑動來選擇錄製或截圖"; break; case 1: toolbar.setTitle("全螢幕截屏"); toolbar.setLogo(R.drawable.capture1); recorder_text="開始全螢幕截屏,按左上角開始擷取"; break; case 2: toolbar.setTitle("區域螢幕截屏"); toolbar.setLogo(R.drawable.ic_phone_android); recorder_text="開始區域螢幕截屏,按左上角開始,點擊螢幕擷取"; break; case 3: toolbar.setTitle("全螢幕錄屏"); toolbar.setLogo(R.drawable.camera_photo); recorder_text="開始全螢幕錄屏,按左上角開始錄屏"; break; } } @Override public void onPageScrollStateChanged(int state) { } }); }
//這裡加入選項,res-menu-menu_main.xml
@Override
public boolean onCreateOptionsMenu(Menu menu) { //讓Icon 顯示,把MenuBuilder的setOptionalIconsVisible設為true就能顯示icon
if(menu.getClass().getSimpleName().equals("MenuBuilder")){ try{ Method m=menu.getClass().getDeclaredMethod("setOptionalIconsVisible",Boolean.TYPE); m.setAccessible(true); m.invoke(menu,true); }catch(Exception e){} } /**這也行,但有紅線error但可運行
if(menu instanceof MenuBuilder){
MenuBuilder m=(MenuBuilder) menu;
m.setOptionalIconsVisible(true); }
*/
getMenuInflater().inflate(R.menu.menu_main, menu); return true; } //這裡處理選項事件
@Override
public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); Log.d("TAG MENU ID",String.valueOf(id)); Log.d("TAG action ID",String.valueOf(R.id.menu2)); //根據選項切換viewpager
if (id == R.id.menu1) {mViewPager.setCurrentItem(0,true);}//return true;}
if (id == R.id.menu2) {mViewPager.setCurrentItem(2,true);}//return true;}
if (id == R.id.menu3) {mViewPager.setCurrentItem(3,true);}//return true;}
if (id == R.id.menu4) {mViewPager.setCurrentItem(1,true);}//return true;}
return super.onOptionsItemSelected(item); } /**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment { /**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number"; //private static final String ARG_SECTION_NUMBER = "ARG_PAGE";
private RelativeLayout mrelativelayout; //主容器
private TextView mtextView; private View rootView=null; public PlaceholderFragment() { } /**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) { //PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); PlaceholderFragment fragment = new PlaceholderFragment(); fragment.setArguments(args); return fragment; } @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(rootView==null) { rootView = inflater.inflate(R.layout.fragment_main, container, false); } mrelativelayout=(RelativeLayout) rootView.findViewById(R.id.RL); mtextView = (TextView) rootView.findViewById(R.id.textView); //mtextView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER)));
//注意不能用getArguments().getInt(ARG_SECTION_NUMBER)取得當前page取得當前page
//因為這會下到欲轉的頁面一開始會是0,1
//我們用addOnPageChangeListeneraddOnPageChangeListener來取得當前page
//textView.setText(String.valueOf(getArguments().getInt(ARG_SECTION_NUMBER)));
mrelativelayout.removeAllViews();//一開始先清除頁面上所有元件
//根據頁面需要加上元件
if(getArguments().getInt(ARG_SECTION_NUMBER)==1){add_pag1(rootView);} if(getArguments().getInt(ARG_SECTION_NUMBER)==2){add_pag2(rootView);} if(getArguments().getInt(ARG_SECTION_NUMBER)==3){add_pag3(rootView);} if(getArguments().getInt(ARG_SECTION_NUMBER)==4){add_pag4(rootView);} //Log.d("TAG",String.valueOf(getArguments().getString("title")));
//if(getArguments().getInt(ARG_SECTION_NUMBER)==2){add_pag2(rootView);}
return rootView; } //頁面1,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉
private void add_pag1(View v){ mrelativelayout.removeAllViews(); mrelativelayout.addView(mtextView); mtextView.setText("作者:Y.P.LIN"); Log.d("TAG","screen 4"); } //頁面2,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉
private void add_pag2(View v){ mrelativelayout.removeAllViews(); mrelativelayout.addView(mtextView); mtextView.setText("全螢幕截圖"); Log.d("TAG","screen 1"); } //頁面3,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉
private void add_pag3(View v){ mrelativelayout.removeAllViews(); mrelativelayout.addView(mtextView); mtextView.setText("區域螢幕截圖"); Log.d("TAG","screen 2"); } //頁面4,新增元件位置時,xml不要相對會變動的元件,否則位置會跑掉
private void add_pag4(View v){ mrelativelayout.removeAllViews(); mrelativelayout.addView(mtextView); mtextView.setText("全螢幕錄屏"); Log.d("TAG","screen 3"); } }//class PlaceholderFragment /**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages. */
public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override
public Fragment getItem(int position) { // getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1); } //幾個頁面 @Override public int getCount() { // Show 3 total pages. return 4; } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return "SECTION 0"; case 1: return "SECTION 1"; case 2: return "SECTION 2"; case 3: return "SECTION 3"; } return null; } } }
read more...
訂閱:
文章 (Atom)