顯示具有 fragment 標籤的文章。 顯示所有文章
顯示具有 fragment 標籤的文章。 顯示所有文章

2017年4月19日 星期三

[Android] Fragment之間切換

我們在Activity可以用startActivity() / startActivityForResult()來切換Activity之間

但是Fragment之間要怎麼切換呢?

這邊使用TabHost 來分成多頁,在每個Fragment之間要怎麼切換,就是個問題

我們使用FragmentTransaction+FragmentManager來處理這個問題

example:

Fragment galleryFragment = new GalleryFragment();
Bundle args = new Bundle();
args.putString("參數名稱", 參數);
galleryFragment.setArguments(args);//pass argument to target fragment
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();

ft.replace(R.id.container,galleryFragment);
ft.addToBackStack(null);
ft.commit();

GalleryFragment是目的fragment,而這段則是寫在來源fragment

但這邊可能會遇到一個問題(bug)

No View Found For id ...... (illegalStateException)

該怎辦呢?
問題就出在ft.replace(R.id.container,galleryFragment)這行
這個R.id.container必須要在TabHost(Parent)裡面的XML有個FrameLayout

看一下這個TabHost的xml:

<android.support.v4.app.FragmentTabHost    xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@android:id/tabhost"    android:layout_width="match_parent"    android:layout_height="match_parent"    >
    <LinearLayout        android:orientation="vertical"        android:layout_width="match_parent"        android:layout_height="match_parent"        >
        <!-- Tab標籤 -->        <TabWidget            android:id="@android:id/tabs"            android:orientation="horizontal"            android:layout_width="match_parent"            android:layout_height="wrap_content"            />

        <FrameLayout            android:id="@android:id/tabcontent"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:visibility="gone"            />

        <!-- 標籤內容顯示區塊 -->        <FrameLayout            android:id="@+id/container"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_weight="1"            />

    </LinearLayout>

</android.support.v4.app.FragmentTabHost>

有看到@+id/container這個,如果你隨便打content_frame(直接照抄之類的容易出現這樣的錯誤)

就會找不到這個id 因此就在跳轉的時候出現錯誤,所以搞懂了這個問題以後,就可以自己改寫囉!

end

2015年4月29日 星期三

[iOS] Tab Bar分頁+UDP通訊

不知道怎樣寫分頁或是怎樣做UDP通訊嗎??

最近好不容易弄出了一點樣子,把它記錄起來,以免以後忘記.

首先分頁是使用tab bar元件-GG Tab Bar(https://github.com/Goles/GGTabBar)

,讓分頁切成四塊(同時建立四個.h+.m+.xib檔案)

可以看到有分了Page1,2,3,4分頁,以及對應的xib檔


首先,先在各個page.m裡面新增:


- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.tabBarItem = [[UITabBarItem alloc] initWithTitle:nil
                                                        image:[UIImage imageNamed:@"user_normal"]
                                                selectedImage:[UIImage imageNamed:@"user_pressed"]];
    }
    return self;
}

(image的部份就是要自己找圖或是下載source code,名稱自行調整,但需要對應到Images.xcassets裡面的檔案名稱)


step2: AppDelegate.h+m的部份

AppDelegate.h

#import <UIKit/UIKit.h>

#import "AsyncUdpSocket.h"
#define global ((AppDelegate *)[[UIApplication sharedApplication] delegate])

@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    AsyncUdpSocket *udpSocket;
    NSTimer *timer;
    long tag;
}
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic,retain) NSMutableArray *globalData;


@end


AppDelegate.m


#import "AppDelegate.h"
#import "GGTabBarController.h"
#import "Page1.h"
#import "Page2.h"
#import "Page3.h"
#import "Page4.h"


@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    NSLog(@"open");
    
    global.globalData = [[NSMutableArray alloc] initWithCapacity:300];
    
    udpSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
    NSError *error = nil;
    [udpSocket bindToPort:2601 error:&error]; //綁定一個port 讓發送的source port / 指定接收的port 都是這一個
    [udpSocket receiveWithTimeout:-1 tag:0];//Start listening for a UDP packet.
    timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(sender) userInfo:nil repeats:YES];
    
    GGTabBarController *tabBar = [[GGTabBarController alloc] init];
    
    Page1 *vc1 = [[Page1 alloc] init];
    Page2 *vc2 = [[Page2 alloc] init];
    Page3 *vc3 = [[Page3 alloc] init];
    Page4 *vc4 = [[Page4 alloc] init];
    
    tabBar.viewControllers = @[vc1, vc2, vc3, vc4];
    self.window.rootViewController = tabBar;
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

//Server 接收
-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
    //NSLog(@"in server");
    Byte *convert_to_byte = (Byte *)[data bytes];
    int length = data.length;
    //NSLog(@"length = %d",length);
    int receive[length];
    NSNumber *number;
    NSMutableArray *intArray = [[NSMutableArray alloc] init];
    
    for (int i = 0 ; i < [data length]; i++) {
        //printf("conver to byte = %d\n",convert_to_byte[i]);
        int combine = (int)convert_to_byte[i];
        //NSLog(@"%ld",combine);
        receive[i] = combine;
        number =[NSNumber numberWithInt:combine];
        [intArray addObject:number];
        NSLog(@"number =%@",number);
        //[global.globalData addObject:number];
        //NSLog(@"i=%@",global.globalData[i]);
        
        NSLog(@"%d",receive[i]);//詳細接收
    }
    [global.globalData setArray:intArray];
    [intArray removeAllObjects];
    
    for(int i = 0; i < global.globalData.count; i++){
        NSLog(@"i=%@",[global.globalData objectAtIndex:i]);
    }
    
    NSLog(@"global-data count= %lu",(unsigned long)global.globalData.count);
    
    //receive要解析,
    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];
    [udpSocket receiveWithTimeout:-1 tag:0];
    return YES;
}


-(void) sender{
    //NSLog(@"timer");
    const unsigned char byte[] = {80,67,77,71,1,69,78,68};
    NSData *data = [NSData dataWithBytes:byte length:sizeof(byte)];
    [udpSocket sendData:data toHost:@"210.202.53.147" port:2601 withTimeout:-1 tag:tag];
}

@end

step3 : 建立udp通訊

這部份在前幾篇有講到附上網址:udp通訊part

(不過這部份已經有寫在上面了)



做完通訊,又有tab bar分頁功能以後,就是把分頁內容建立好囉!

教學到此結束,end.


2015年2月2日 星期一

[Android] ViewPager的簡易使用方法,Fragment,以及切換分頁監聽實作

之前看一些可以分頁的APP又有動畫,都只是把程式碼抓下來修改一下,就用了.

今天終於稍微搞懂一些裡面的用法.

首先MainActivity.java

1.第一目標 ------ extends FragmentActivity

然後裡面宣告一個PagerAdapter 的變數

2.PagerAdapter宣告的時候一定是出現錯誤,因為你還沒建立一個名為PagerAdapter的型態的

class 所以我們就多建一個java檔名為PagerAdapter 記得要implement FragmentPagerAdapter!

import java.util.List;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class PagerAdapter extends FragmentPagerAdapter {


private List<Fragment> fragments;

public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
// TODO Auto-generated constructor stub
this.fragments = fragments;
}

@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return this.fragments.get(arg0);
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return this.fragments.size();
}

}

裡面就是實作他需要的方法(可以按add unimplement method來建立)

3.把PagerAdapter建立起來以後就是要加入分頁了!

在onCreate()裡面新增:

(初始化pager)
private void initialisePaging() {
// TODO Auto-generated method stub
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName()));
fragments.add(Fragment.instantiate(this, Fragment2.class.getName()));
mPagerAdapter = new PagerAdapter(this.getSupportFragmentManager(),
fragments);

ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(mPagerAdapter);

myPageChange = new myPageChangeListenter();//new
pager.setOnPageChangeListener(myPageChange);//建立監聽
}

這邊就是建立一個list 然後放進去兩個class(也就是未來的兩個分頁)

當然要在外面宣告兩個變數

private PagerAdapter mPagerAdapter;
public myPageChangeListenter myPageChange;//先宣告一個該型態的變數

不然他會抓不到

--------------------------------------------分隔線------------------------------------------------------

如果到這邊都OK的話,你已經完成一半了.

接下來還要設定監聽(滑動的時候要監聽,不然系統不會去抓你滑到哪一頁了)

我們在上面有用pager.setOnPageChangeListener(myPageChange);來建立監聽

下面當然是要實做這個 myPageChangeListener

public class myPageChangeListenter implements OnPageChangeListener{

@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
//Log.d("change to page = ",Integer.toString(arg0));
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
//Log.d("scroll to page = ","here");
}

@Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
Log.d("select to page = ",Integer.toString(arg0));
//第一頁為0,第二頁為1
}
}

}

非常簡單,我個人習慣使用onPageSelected來設定動作,都可以透過Log來測試你想要的觸發

--------------------------------------------分隔線------------------------------------------------------

有了 監聽 /  PagerAdapter  還需要分頁.....

這部分最大的問題就是在於抓不到該分頁的元件id,當然後來解決了(不然也不會發文)

package com.example.viewpagerexample;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.civetcat.weather.library.WeatherInfo;
import com.civetcat.weather.library.YahooWeather;
import com.civetcat.weather.library.YahooWeather.SEARCH_MODE;
import com.civetcat.weather.library.YahooWeatherInfoListener;

public class Fragment1 extends Fragment implements YahooWeatherInfoListener{

    public View view;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
if (container == null) {
return null;
}

view = inflater.inflate(R.layout.fragement1_layout,container, false);

               //中間可以使用
               TextView txv = (TextView) view.findViewById(R.id.xxx);
               //來抓取id

return view;
}
}

Fragment2 也是類似的就不多貼了!

至於layout的部分:

(viewpager_layout.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
   
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        />
</LinearLayout>

這部分是重點!!

看我們這邊在MainActivity.java裡面設定的

setContentView(R.layout.viewpager_layout);

因此該xml檔必須要有ViewPager 不然怎麼去抓呢? 

大致上就是這樣,把寫了一個天氣的範例放上來,可以參考看看


END