以下のように、ただそのままキャプチャするより良く見えるかもしれません
上のリンクをクリックして、メッセージボックスの OK ボタンをクリックすると、このページを斜めにします。 斜めになっても、WEBページである事にはかわりは無いので、テキスト選択もできますし、リンクも生きています。
ブックマークレットに関する記事
関連する記事
最近は、セキュリティに厳密になったサイトが増えたので、そのページに埋め込む事ができなくなりつつあります。なので、windows.prompt で検索文字列を入力させて直接 Google を呼び出すようにしました。 ブックマークレットの登録は、ブックマークバーを表示して、その上にドラッグ・ドロップするのが簡単です。 ドメイン内検索 便利な「切り替え機能」 切り替えボタンで、深い階層へ移動して、その階層にあるページのみ検索できるようになります。アプリケーションの「オンラインマニュアル」の内容検索に絶大な効果を発揮します 表示しているドメインを検索するフォームを埋め込みます ※ 切り替えで、階層を変更可能です インストールは、ブックマークバー等へ入れるだけですし、アンインストールは削除するだけです。 注意 : 実行本体は、lightbox.on.coocan.jp にありますので、nifty のラクーカンが落ちていると動きません。( https ページへのアクセスには、さくらサーバーを使用しています ) ブックマークレットに関する記事
Java に精通してはいないので、Windows のメッセージ処理の発想で作成しています。MessageBox 内の onYesClick メソッドは抽象メソッドなので、使用する際に必ず記述する必要がありますが、onNoClick メソッドは 内部で実装しているので、書いても書かなくても OK です。 onYesClick と onNoClick は、該当場所で、CTRL + O で Override 用のダイアログが表示されるので選択して実装します。onYesClick は必須ですが、onNoClick は省略可能で、Yes ボタン以外のアクションの場合に呼び出されます。
import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; /** * Created by lightbox on 2015/06/11. */ public abstract class MessageBox { private AlertDialog alertDialog = null; public MessageBox() { } // YES or NO メッセージボックス( タイトルとメッセージ両方指定) public void show(Activity context,String title,String message) { // ダイアログ作成用オブジェクト作成 AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); alertDialogBuilder.setTitle(title); alertDialogBuilder.setMessage(message); // YES ボタン作成 alertDialogBuilder.setPositiveButton("YES", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { MessageBox.this.onYesClick(dialog); } }); // NO ボタン作成 alertDialogBuilder.setNegativeButton("NO", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { MessageBox.this.onNoClick(dialog); } }); alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { MessageBox.this.onNoClick(dialog); } }); alertDialogBuilder.setCancelable(true); // アラートダイアログを作成します alertDialog = alertDialogBuilder.create(); alertDialog.show(); } // 確認 メッセージボックス( メッセージのみ ) public void show(Activity context,String message) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); alertDialogBuilder.setTitle("確認"); alertDialogBuilder.setMessage(message); alertDialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { MessageBox.this.onYesClick(dialog); } }); alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { MessageBox.this.onNoClick(dialog); } }); alertDialogBuilder.setCancelable(true); // アラートダイアログを作成します alertDialog = alertDialogBuilder.create(); alertDialog.show(); } // Override は必須 abstract void onYesClick(DialogInterface dialog); // Override を省略できるように protected protected void onNoClick(DialogInterface dialog) { } }
呼び出し1 / OK ボタンのみ メッセージボックス以外をタップしたり、戻ったりするとキャンセルとなります。show メソッドの引数が、context と メッセージと二つだけの時にこの処理となります。
// 単純確認メッセージボックス new MessageBox(){ @Override void onYesClick(DialogInterface dialog) { // 処理 } }.show(MainActivity.this, "こんにちは");
呼び出し2 / YES ボタンと NO ボタン NO ボタンをタップするか、メッセージボックス以外をタップするか、戻ったりいるとキャンセルとなります。show メソッドの引数が、context と タイトルとメッセージの時にこの処理となります。
// 単純確認メッセージボックス new MessageBox(){ @Override void onYesClick(DialogInterface dialog) { // 処理 } }.show(MainActivity.this, "タイトル","メッセージ");
Android Studio + Android 5.1(Lollipop) これでは、リストビュー内のコンテンツに汎用性が全くありませんが、そういう複雑なリストビューはきちんと設計して誰でも使えるようにするべきなので、これはこれである意味汎用性があると思います。
package app.lightbox.winofsql.jp.listviewa; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; public class MainActivity extends Activity { class MyData { public String title = null; public String url = null; public MyData(String myTitle,String myUrl) { title = myTitle; url = myUrl; } @Override public String toString() { return title; } } private MyData[] mydata = new MyData[] { new MyData("Yahoo! ニュース","http://news.yahoo.co.jp/"), new MyData("Yahoo! 雨雲ズームレーダー","http://weather.yahoo.co.jp/weather/zoomradar/"), new MyData("ねとらぼ","http://nlab.itmedia.co.jp/") }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // リストビュー(MyData)用のアダプターを作成 ArrayAdapter<MyData> adapter = new ArrayAdapter<MyData>(MainActivity.this, android.R.layout.simple_list_item_1); // データをセット adapter.addAll( mydata ); // リストビューに適用 ListView listView = (ListView) MainActivity.this.findViewById(R.id.listView); listView.setAdapter(adapter); // リストビューのアイテムがクリックされた時の処理 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // クリックされたアイテムを取得 MyData mydata = (MyData)parent.getItemAtPosition(position); // LogCatに表示 Log.i("lightbox", mydata.title); Log.i("lightbox", mydata.url); // URL を開く callBrowser(mydata.url ); } }); } private void callBrowser( String url ) { // ブラウザの呼び出し Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); return; } // 対応するアプリが無い Toast.makeText( MainActivity.this, "ブラウザを呼び出せません", Toast.LENGTH_LONG ).show(); return; } }
※ 配列部分を外部 JSON にすれば読み替えは簡単にできる予定。 画面定義
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/listView" android:layout_alignParentTop="true" android:layout_alignParentStart="true"/> </RelativeLayout>
リストビューの一行ぶんの View の定義としては、android.R.layout.simple_list_item_1 と android.R.layout.simple_list_item_2 を使用しています。たいていは android.R.layout.simple_list_item_1 でまかなえると思いますが、項目が二つの場合が必要な場合として、SimpleAdapter が最も簡潔に書けるのでそれを利用しています。 ArrayAdapter で、android.R.layout.simple_list_item_2 に対応するのには、ArrayAdapter を継承したユーザクラスが必要になりますが、ここでは使用していません。 全体のコードは こちら で参照して下さい ArrayAdapter で文字列を一つづつ追加
private ArrayAdapter<String> strArrayAdapter = null; private ListView listview = null; private String [] strData1 = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listview = (ListView) MainActivity.this.findViewById(R.id.listView); // 単純な文字列配列用 strArrayAdapter = new ArrayAdapter<String>( MainActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1 ); // タイトルデータ(1) strData1 = new String[]{ "Yahoo! ニュース","Yahoo! 雨雲ズームレーダー", "ねとらぼ","GIGAZINE","Twitter","OneDrive", "楽天市場","ウィキペディア","Yahoo!テレビ", "@IT","Stack Overflow","Android Developers" }; }
// ArrayAdapter をクリア strArrayAdapter.clear(); for( int i = 0; i < strData1.length; i++ ) { strArrayAdapter.add(strData1[i]); } listview.setAdapter(strArrayAdapter);
ArrayAdapter で配列を一括で追加 前提となるパーツは一つ前と同じです。配列が固定で既に作成されている場合にすぐに投入できます。外部から JSON で読み込んで、結果的に配列が作成されているような場合に最適です。
// ArrayAdapter をクリア strArrayAdapter.clear(); // でき上がっている配列をそのままセット strArrayAdapter.addAll(strData1); listview.setAdapter(strArrayAdapter);
ArrayAdapter で List を一括で追加 既にできあがっているデータが配列ではなく、List インターフェイスを持つ場合に使用します ここでは、テストなので配列から List を作成して使用しています
// ArrayAdapter をクリア strArrayAdapter.clear(); // 配列から List を作成 List<String> list = Arrays.asList(strData1); // List を指定する addAll strArrayAdapter.addAll(list); listview.setAdapter(strArrayAdapter);
ArrayAdapter で 内部に別の情報を持つ 専用のクラスを作成して、それ用の ArrayAdapter で処理します。表示は 1つの内容しかできませんが、内部に別の情報を持つので、行をクリックした時にそれを使用する事ができます
private ArrayAdapter<MyData> arrayMyData = null; private ListView listview = null; private String [] strData1 = null; private String [] strData1Url = null; // ListView にセットする配列用クラス class MyData { public String title = null; public String url = null; public MyData(String myTitle,String myUrl) { title = myTitle; url = myUrl; } // toString で呼び出された内容が ListView に表示されます @Override public String toString() { return title; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ListView のインスタンスを取得 listview = (ListView) MainActivity.this.findViewById(R.id.listView); // 専用クラス用 arrayMyData = new ArrayAdapter<MyData>( MainActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1 ); // タイトルデータ(1) strData1 = new String[]{ "Yahoo! ニュース","Yahoo! 雨雲ズームレーダー", "ねとらぼ","GIGAZINE","Twitter","OneDrive", "楽天市場","ウィキペディア","Yahoo!テレビ", "@IT","Stack Overflow","Android Developers" }; // タイトルデータ(1) の URL データ strData1Url = new String[]{ "http://news.yahoo.co.jp/", "http://weather.yahoo.co.jp/weather/zoomradar/", "http://nlab.itmedia.co.jp/", "http://gigazine.net/", "http://twitter.com/", "http://onedrive.live.com/", "http://www.rakuten.co.jp/", "https://ja.wikipedia.org", "http://tv.yahoo.co.jp/", "http://www.atmarkit.co.jp/", "http://stackoverflow.com/", "http://developer.android.com/index.html" }; }
// ArrayAdapter をクリア arrayMyData.clear(); // 配列から作成 for( int i = 0; i < strData1.length; i++ ) { arrayMyData.add(new MyData(strData1[i],strData1Url[i])); } listview.setAdapter(arrayMyData);
SimpleAdapter で二つの情報を表示 ArrayAdapter よりも汎用性がなくなります( メソッドでできる事がほとんどなくなってしまいます )が、手早く複数項目を持つ View への対応が簡単です。
private ListView listview = null; private String [] strData1 = null; private String [] strData1Url = null; private SimpleAdapter itemsAdapter = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ListView のインスタンスを取得 listview = (ListView) MainActivity.this.findViewById(R.id.listView); // タイトルデータ(1) strData1 = new String[]{ "Yahoo! ニュース","Yahoo! 雨雲ズームレーダー", "ねとらぼ","GIGAZINE","Twitter","OneDrive", "楽天市場","ウィキペディア","Yahoo!テレビ", "@IT","Stack Overflow","Android Developers" }; // タイトルデータ(1) の URL データ strData1Url = new String[]{ "http://news.yahoo.co.jp/", "http://weather.yahoo.co.jp/weather/zoomradar/", "http://nlab.itmedia.co.jp/", "http://gigazine.net/", "http://twitter.com/", "http://onedrive.live.com/", "http://www.rakuten.co.jp/", "https://ja.wikipedia.org", "http://tv.yahoo.co.jp/", "http://www.atmarkit.co.jp/", "http://stackoverflow.com/", "http://developer.android.com/index.html" }; }
// 内部データを作成 List list = new ArrayList<Map<String, ?>>(); for( int i = 0; i < strData1.length; i++ ) { Map map = new HashMap(); // 名前は文字列で適当に付けます( item1, item2 ) map.put("item1", strData1[i]); map.put("item2", strData1Url[i]); list.add(map); } // 複数項目のビュー用のインスタンス itemsAdapter = new SimpleAdapter( // 1) MainActivity.this, // 2) list, // 3) 二つの項目を持つビュー android.R.layout.simple_list_item_2, // 4) ここで項目を一致させる new String[] { "item1", "item2" }, // 5) 実際のビューの id と一致させる new int[] { android.R.id.text1, android.R.id.text2 } ); listview.setAdapter(itemsAdapter);
クリックした時の処理 URL 情報を持つ二つのパターンでは、ブラウザを呼び出しています。
// クリックした時のイベント作成 listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // クリックされたビューの内部データ Object data = (Object)parent.getItemAtPosition(position); // クラス名を取得 Log.i("lightbox","data type:" + data.getClass().getName()); String myClass = "app.lightbox.winofsql.jp.listviewaction.MainActivity$MyData"; String simple = "java.util.HashMap"; // 専用クラスの場合 if ( myClass.equals(data.getClass().getName()) ) { MyData myData = (MyData)data; Log.i("lightbox", "title:" + myData.title); Log.i("lightbox", "url:" + myData.url); // ブラウザの呼び出し callBrowser(myData.url); return; } if ( simple.equals(data.getClass().getName()) ) { Map map = (Map)data; Log.i("lightbox", "title:" + map.get("item1")); Log.i("lightbox", "url:" + map.get("item2")); // ブラウザの呼び出し callBrowser(map.get("item2").toString()); return; } // 単純な文字列の場合 String myData = (String)data; Log.i("lightbox", "text:" + (String)data); } });
ただ表示するだけなので、Bitmap も Drawable もあまり違いはありませんが、ただ読みたい場合は Drawable のほうが簡潔です。(Bitmap の場合は書く事が多いぶん、メタデータのみを取得する事ができますね) MainActivity
package app.lightbox.winofsql.jp.storageaccess; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.ImageView; import java.io.InputStream; import java.net.URL; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ボタンのイベント Button button = (Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new AsyncTask<String, Void, Bitmap>() { // 非同期処理 @Override protected Bitmap doInBackground(String... params) { Bitmap image = null; BitmapFactory.Options options; try { // インターネット上の画像を取得して、Bitmap に変換 URL url = new URL(params[0]); options = new BitmapFactory.Options(); // 実際に読み込む options.inJustDecodeBounds = false; InputStream is = (InputStream) url.getContent(); image = BitmapFactory.decodeStream(is, null, options); is.close(); } catch (Exception e) { Log.i("button", e.getMessage()); } return image; } // UI スレッド処理 @Override protected void onPostExecute(Bitmap image) { super.onPostExecute(image); // Bitmap 取得に成功している場合は表示します if (image != null) { ImageView imageView = (ImageView) MainActivity.this.findViewById(R.id.imageView); imageView.setImageBitmap(image); } } }.execute("https://goo.gl/fc07Q6"); // JPEG 画像の 短縮 URL } }); // ボタンのイベント Button button2 = (Button) this.findViewById(R.id.button2); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new AsyncTask<String, Void, Drawable>() { // 非同期処理 @Override protected Drawable doInBackground(String... params) { Drawable image = null; try { // インターネット上の画像を取得して、Drawable に変換 URL url = new URL( params[0] ); InputStream is = (InputStream)url.getContent(); image = Drawable.createFromStream(is, ""); is.close(); } catch(Exception e) { Log.i("button", e.getMessage()); } return image; } // UI スレッド処理 @Override protected void onPostExecute(Drawable image) { super.onPostExecute(image); // Bitmap 取得に成功している場合は表示します if (image != null) { ImageView imageView = (ImageView) MainActivity.this.findViewById(R.id.imageView); imageView.setImageDrawable(image); } } }.execute("https://goo.gl/WNzpRl"); // JPEG 画像の 短縮 URL } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
画面定義
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentStart="true" android:id="@+id/linearLayout"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bitmap" android:id="@+id/button" android:layout_alignParentTop="true" android:layout_alignParentStart="true" android:layout_weight="1"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Drawable" android:id="@+id/button2" android:layout_alignParentTop="true" android:layout_weight="1"/> </LinearLayout> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/imageView" android:layout_below="@+id/linearLayout" android:layout_alignParentStart="true" android:scaleType="fitStart"/> </RelativeLayout>
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。 Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。 また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。 ※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです 対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。 ※ エキスパートモードで表示しています アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります<% if:page_name eq 'archive' -%> アーカイブページでのみ表示される内容 <% /if %> <% if:page_name eq 'category' -%> カテゴリページでのみ表示される内容 <% /if %> <% if:page_name eq 'tag' -%> タグページでのみ表示される内容 <% /if %>この記述は、以下の場所で使用します
|