@blog.justoneplanet.info

日々勉強

AccessoryViewをカスタマイズする

setAccessoryViewしただけだとタップした時にaccessoryButtonTappedForRowWithIndexPathが発火しなくなるので以下のようにする。

// create cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // call cell
    UITableViewCellFixed *cell = (UITableViewCellFixed *)[tableView dequeueReusableCellWithIdentifier:@"table_cell"];
    if (cell == nil) {// create cell
        cell = [[[UITableViewCellFixed alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"table_cell"] autorelease];
    }
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setFrame:CGRectMake(0, 0, 26, 26)];
    [button setBackgroundImage:[UIImage imageNamed:@"arrow.png"] forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor clearColor]];
    [button addTarget:self action:@selector(accessoryButtonTapped:withEvent:) forControlEvents:UIControlEventTouchUpInside];
    [cell setAccessoryView:button];
    return cell;
}
- (void)accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event
{
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:[[[event touchesForView: button] anyObject] locationInView:self.tableView]];
    if (indexPath == nil) {
        return;
    }
    [self.tableView.delegate tableView: self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
}

EC2にexpressを入れる

■インストール

yum install openssl-devel gcc-c++ make#前準備
wget http://nodejs.org/dist/v0.6.11/node-v0.6.11.tar.gz
tar xvzf node-v0.6.11.tar.gz
cd node-v0.6.11
./configure
make
make install
curl http://npmjs.org/install.sh | sh
npm install -g express
express sample
cd sample
npm install

./app.js

たまたま80番開いていたので以下のようにして80番で繋がるようにする。

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes');

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

app.get('/', routes.index);

app.listen(80);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

■起動

node app.js

http://ec2-123-123-123-123.ap-northeast-1.compute.amazonaws.com/などで自分のインスタンスにアクセスすれば見れる。

■socket.ioを使う

./package.json

以下のように編集する。

{
    "name": "application-name"
  , "version": "0.0.1"
  , "private": true
  , "dependencies": {
      "express": "2.5.8"
    , "jade": ">= 0.0.1"
    , "socket.io": "*" 
  }
}

./sampleで以下のコマンドを実行する。

npm install

./app.js

サーバー側のコードをapp.jsの最後尾に付加する。

var io = socketio.listen(app)
   ,count = 0;
io.sockets.on('connection', function(socket){
  count++;
  io.sockets.emit('count change', count);
  socket.on('disconnect', function() {
    count--;
    socket.broadcast.emit('count change', count);
  }
  );  
});

./views/layout.jade

クライアント側の処理を書き加える。

!!!
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
    script(type='text/javascript', src='http://code.jquery.com/jquery.min.js')
    script(type='text/javascript', src='/socket.io/socket.io.js')
    script(type='text/javascript')
      var socket = io.connect();
      socket.on('count change', function(count) {
        $('#count').text(count);
      }); 
  body!= body

./views/index.jade

表示用に要素を追加する。

#page
  #headerArea
    h1= title
    p Welcome to #{title}
    p 現在このページを見ている人は
    span#count
    人います。

■ejsを使う

既存のhtmlコードを使用するときにhamlにするのは手間なのでejsを使う。

./package.json

以下のように編集する。

{
    "name": "application-name"
  , "version": "0.0.1"
  , "private": true
  , "dependencies": {
      "express": "2.5.8"
    , "jade": ">= 0.0.1"
    , "socket.io": "*" 
    , "ejs": "*" 
  }
}

./app.js

以下のようにして、テンプレートエンジンをjadeからejsに変更する。

/**
 * Module dependencies.
 */

var express  = require('express')
  , socketio = require('socket.io')
  , ejs      = require('ejs')
  , routes   = require('./routes');

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.set('view options', {layout : false});
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

せっかくなんでルーティングも変更してみる。

app.get('/', routes.index);
app.get('/hoge', function(req, res) {
  res.render('hoge.ejs', { title: 'My Site' }); 
});

参考

./views/hoge.ejs

あとは以下のようにテンプレートファイルを用意する。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8" />
<title><%= title %></title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect();
socket.on('count change', function(count) {
    $('#count').text(count);
});
</script>
</head>

<body>
<h1><%= title %></h1>
<p>現在このページを見ている人は<span id="count"></span>人います。</p>
</body>
</html>

以下のようなURLでアクセスができるようになる。

http://ec2-123-123-123-123.ap-northeast-1.compute.amazonaws.com/hoge

fragmentに値を渡す

■渡す側

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();

SearchFragment fragment = (SearchFragment) Fragment.instantiate(getActivity(), SearchFragment.class.getName(), null);
Bundle bundle = new Bundle();
bundle.putString("word", word);
fragment.setArguments(bundle);

ft.replace(R.id.content, fragment).addToBackStack("result");
ft.commit();
getActivity().getSupportFragmentManager().executePendingTransactions();

■受け取り側

mWord = getArguments().getString("word");

SimpleCursorAdapterを元に作ったListViewにfilterを付加する

以下のように実装しているとする。

mListView.setTextFilterEnabled(true);
mAdapter = new SimpleCursorAdapter(
        getActivity().getApplicationContext(),
        R.layout.list,
        null,
        new String[]{Helper.FACE, Helper.TAG},
        new int[]{R.id.list_face, R.id.list_tag}
);
mListView.setListAdapter(mAdapter);

以下のようにして表示されているリストをフィルタリングする。

public void onTextChanged(CharSequence s, int start, int before, int count) {
    mListView.setFilterText(s.toString);
}

これだけでは上手く動作しない。

■解決策

adapterをListViewにセットする前に以下のように記述する必要がある。

mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
    @Override
    public Cursor runQuery(CharSequence constraint) {
        String word = "%" + constraint.toString() + "%";
        Cursor cursor = getActivity().managedQuery(
            Provider.URI,
            new String[]{Helper.ID, Helper.FACE, Helper.TAG, Helper.CREATED},
            "`" + Helper.FACE + "` LIKE ? OR `" + Helper.TAG + "` LIKE ?",
            new String[]{word, word},
            Helper.CREATED + " DESC"
        );
        return cursor;
    }
});

Honeycomb以降でcursorを扱う

startManagingCursorはdeprecatedになったので、Honeycomb以降のandroidでは以下のような例外が発生する。

java.lang.RuntimeException: Unable to resume activity
java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor@40740c58

LoaderManagerとCursorLoaderを使うか、自前でcursor.close()を呼び出すかしなければならない。

参考

PHPで不正な閉じタグを見つける

ループは1回にできると思うけどまぁとりあえず。

<?php
$str = <<<EOD
<html>
<body>
<center>
<form action="confirm.php" method="get">
<input type="text" name="name"><br>
<input type="submit" value="submit">
</center>
</form>
</body>
</html>
EOD;

preg_match_all("/<.*?>/", $str, $matches);
//var_dump($matches);
$ary = array();
$stack = array();

foreach ($matches[0] as $key => $value) {
    array_push($ary, $value);
}

foreach ($ary as $key => $value) {
    if (preg_match("/<\/([a-zA-Z]+)/", $value, $tag)) {
#        echo "$value\n";
#        var_dump($tag[1]);
        $isFoundClose = false;
        foreach ($ary as $k => $v) {
            if (preg_match("/<{$tag[1]}/", $v)) {
#                echo "match\n";
                $isFoundClose = true;
                array_splice($ary, $k, $key - $k);
                break;
            }   
        }   
        if (!$isFoundClose) {
            echo "error:$value\n";
        }   
    }   
    else {

    }   
}