Blog -
買いました!
アンドロイドの開発環境は日々変わっていてついていくのは大変ですが。
設計の勘所さえ押さえてしまえば、良いアプリを生み出すこそが出来ます。
活躍している方のノウハウがつまった本、買わずにはいられないです。
画面の解像度毎にランチャアイコンや通知アイコンを用意しますが
少し前のAndroidならそれほど解像度がずば抜けているという事は無かったんですが
最近のタブレットや4.0搭載している物などは今までの余り気に留めなかったサイズがもろに
出てしまいますそこで意外と忘れがち、な各解像度で必要なサイズをまとめました
(若干サイズが違うのは私の主観もあります)
drawable-hdpi | drawable-mdpi | drawable-ldpi | drawable-xhdpi | |
ランチャー |
72*72 | 48*48 | 32*32 | 98*98 |
通知 |
38*38 | 25*25 | 19*19 | 50*50 |
drawable-nodpi はそれぞれ解像度判断されない画像を格納する(ただしストレッチさせると画面に合わせて縮小拡大する)
などなど。
そして作りました。
PC側は流石に、VisualStudioで作りこんでいます。
なかなか快適にオンラインクリップボード出来ますが
GAEが重量課金の為、リリース無料でやるのはちょっと厳しい。
月額にして使ってくれるんだろうか、悩むところ。
寄付もまた微妙だし。
こんな追加機能付けたら行けるだろうか
・特定のパスワードをコピーすると、振動や音で居場所を知らせてくれる(無くした時の発見対策)
GPS起動して座標特定するとか。
・特定のコマンドをコピーすると、写真を撮るとか(画像送信未対応ですが)
・画像のやり取りに対応するとか。
アプリは出来てるんだけど、これは身内で使うかな。
以前、自作ArrayAdapterをListViewにセットして
onListItemClickが発生しない場合の方法を投稿していたがそれでも発生しない場合
(ListActivityで無い場合など)
の対策方法として
ArrayAdapter側のgetViewでView自体にOnClickListenerを設定すると
Activity側のsetOnItemClickListenerが呼ばれる様になる方法を紹介します。
Activity側
onCreateなどで
mListView = (ListView) findViewById(R.id.list); list = new ArrayList(); list = dataSet(this); //<-データをセットする adapter = new CustomAdapter(this, R.layout.item, list); mListView .setAdapter(adapter); registerForContextMenu(mListView ); //アイテムクリック mListView .setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView arg0, View arg1,int position, long arg3) { Toast.makeText(getBaseContext(), list.get(position).getPointLocation(), Toast.LENGTH_SHORT).show(); return; } });
ArrayAdapterのgetViewで
public View getView(final int position, View convertView, final ViewGroup parent) { view = inflater.inflate(R.layout.list_item, parent, false); view.setOnClickListener(new OnClickListener(){ public void onClick(View v){ ((ListView) parent).performItemClick(v, position, (long)0); } }); }
とすると発生する様になります。
TextViewで便利なのはEllipsizingです。
文字列が長ければ末尾に...を付けたり、中間を...に置き換えたりと
いろいろ自動でやってくれますが、これはSingleLineに限っての事
複数行の最後を...に置き換える事は出来ません、検索してもバグなのか仕様なのか
実現する必要性が有ったので、とりあえずTextViewをExtendsして作ってみた
(外国のサイトを参考に修正)
※動作を保障する物ではありません。
public class EllipsizingTextView extends TextView {
private static final String ELLIPSIS = "…";
private static final Pattern DEFAULT_END_PUNCTUATION = Pattern.compile("[\\.,…;\\:\\s]*$", Pattern.DOTALL);
public interface EllipsizeListener {
void ellipsizeStateChanged(boolean ellipsized);
}
private final List<EllipsizeListener> ellipsizeListeners = new ArrayList<EllipsizeListener>();
private boolean isEllipsized;
private boolean isStale;
private boolean programmaticChange;
private String fullText;
private int maxLines;
private float lineSpacingMultiplier = 1.0f;
private float lineAdditionalVerticalPadding = 0.0f;
/**
* The end punctuation which will be removed when appending #ELLIPSIS.
*/
//private Pattern endPunctuationPattern;
public EllipsizingTextView(Context context) {
this(context, null);
}
public EllipsizingTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public EllipsizingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
super.setEllipsize(null);
TypedArray a = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.maxLines });
setMaxLines(a.getInt(0, Integer.MAX_VALUE));
setEndPunctuationPattern(DEFAULT_END_PUNCTUATION);
}
public void setEndPunctuationPattern(Pattern pattern) {
//this.endPunctuationPattern = pattern;
}
public void addEllipsizeListener(EllipsizeListener listener) {
if (listener == null) {
throw new NullPointerException();
}
ellipsizeListeners.add(listener);
}
public void removeEllipsizeListener(EllipsizeListener listener) {
ellipsizeListeners.remove(listener);
}
public boolean isEllipsized() {
return isEllipsized;
}
@Override
public void setMaxLines(int maxLines) {
super.setMaxLines(maxLines);
this.maxLines = maxLines;
isStale = true;
}
public int getMaxLines() {
return maxLines;
}
public boolean ellipsizingLastFullyVisibleLine() {
return maxLines == Integer.MAX_VALUE;
}
@Override
public void setLineSpacing(float add, float mult) {
this.lineAdditionalVerticalPadding = add;
this.lineSpacingMultiplier = mult;
super.setLineSpacing(add, mult);
}
@Override
protected void onTextChanged(CharSequence text, int start, int before,
int after) {
super.onTextChanged(text, start, before, after);
if (!programmaticChange) {
fullText = text.toString();
isStale = true;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (ellipsizingLastFullyVisibleLine()) {
isStale = true;
}
}
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
if (ellipsizingLastFullyVisibleLine()) {
isStale = true;
}
}
@Override
protected void onDraw(Canvas canvas) {
if (isStale) {
resetText();
}
super.onDraw(canvas);
}
private void resetText() {
//String workingText = fullText;
StringBuilder workingText = new StringBuilder(fullText);
boolean ellipsized = false;
Layout layout = createWorkingLayout(fullText);
//Layout layout = createWorkingLayout(workingText);
int linesCount = getLinesCount();
if (layout.getLineCount() > linesCount) {
// We have more lines of text than we are allowed to display.
//workingText = fullText.substring(0, layout.getLineEnd(linesCount - 1)).trim();
workingText = new StringBuilder(fullText.substring(0, layout.getLineEnd(linesCount - 1)));
//workingText = fullText.substring(0, layout.getLineEnd(linesCount - 1));
while (createWorkingLayout(workingText.toString() + ELLIPSIS).getLineCount() > linesCount) {
//int lastSpace = workingText.lastIndexOf(' ');
// int lastSpace = workingText.length() - 1;
//if (lastSpace == -1) {
if ((workingText.length() - 1) == -1) {
break;
}
//workingText = workingText.substring(0, lastSpace - 1);
workingText.delete(workingText.length() - 1, workingText.length());
}
// We should do this in the loop above, but it's cheaper this way.
if(workingText.length() > 2){
//workingText = workingText.substring(0, workingText.length() - 2);
workingText.delete(workingText.length() - 2,workingText.length());
}
//workingText = endPunctuationPattern.matcher(workingText).replaceFirst("");
//workingText = workingText + ELLIPSIS;
//workingText = new StringBuilder(endPunctuationPattern.matcher(workingText.toString()).replaceFirst(""));
workingText.append(ELLIPSIS);
ellipsized = true;
}
if (!workingText.equals(getText())) {
programmaticChange = true;
try {
setText(workingText);
} finally {
programmaticChange = false;
}
}
isStale = false;
if (ellipsized != isEllipsized) {
isEllipsized = ellipsized;
for (EllipsizeListener listener : ellipsizeListeners) {
listener.ellipsizeStateChanged(ellipsized);
}
}
}
/**
* Get how many lines of text we are allowed to display.
*/
private int getLinesCount() {
if (ellipsizingLastFullyVisibleLine()) {
int fullyVisibleLinesCount = getFullyVisibleLinesCount();
if (fullyVisibleLinesCount == -1) {
return 1;
} else {
return fullyVisibleLinesCount;
}
} else {
return maxLines;
}
}
/**
* Get how many lines of text we can display so their full height is visible.
*/
private int getFullyVisibleLinesCount() {
Layout layout = createWorkingLayout("");
int height = getHeight() - getPaddingTop() - getPaddingBottom();
int lineHeight = layout.getLineBottom(0);
return height / lineHeight;
}
private Layout createWorkingLayout(String workingText) {
return new StaticLayout(workingText, getPaint(),
getWidth() - getPaddingLeft() - getPaddingRight(),
Alignment.ALIGN_NORMAL, lineSpacingMultiplier,
lineAdditionalVerticalPadding, false /* includepad */);
}
@Override
public void setEllipsize(TruncateAt where) {
// Ellipsize settings are not respected
}
}
resetText()では表示時に表示対象の文字列を抜き出して後ろに...を足しています。
ただ、正確には日本語の場合フォントで比率などの計算をしないとずれるので2文字分引いている。
とりあえず動いたが、処理が遅いのでリファクタリングが必要かな。
※ご利用は自己責任で。
コーディングしていると普通に
if(str != null){
}
if(str.length() > 0){
}
などで文字列を判断していますが、上記だと””が引っかからないなど
if文を二重にしたりしていませんか?(null判断とlengthは同じifにかけられません)
そこで便利なのが
TextUtils.isEmpty(str)
Nullもlength 0も同時に判断してくれます、もちろんnullもしくはlength=0ならtrueが返ります。
もう少し早く気付けば良かった。。。
Androidで開発していると何かとListActivityを使いますが、画像を入れたり
ちょっとカッコよく表示したり、自作のLayoutを使いたくなります。
そこで、ArrayAdapterを作ってListActivityにセットしてさあと思いきやいくらクリックしても
onListItemClickが発生しないという事態になる方も多いはず。
原因は、ListActivityのItemにArrayAdapterが紐づいている訳ですので
ArrayAdapterで発生しない限り、ListActivityには通知されません。
そこで、発生させる方法として・・・
ArrayAdapter側に「OnClickListener」をインプリメントして「onClick」メソッドを追加します。
すると、ListActivityの「onListItemClick」が発生するようになります。
CM4IS01にBluetoothのデバイスを実装しようと思って、CyanogenModを取得しようと考えた。
ソースを取得するのにgitサーバが落ちたままなの気づかなくてかなり苦労してしまった。
repo syncを実行すると
android.git.kernel.org[0:149.20.77]:error=Connection refused ...
fatal:unable to connect a socket(Connection refused)
が発生して進まない、ポート9418が開いてないのかと思い調べるが問題無し、いろいろ調べるとサーバが落ちたままだそうで。
ocdeaurowa.orgが非公式ミラーをしているのそちらを利用させてもらう。
repoで取得したManifest.xmlを編集して
fetch="git://android.git.kernel.org/" の行を
fetch="git://codeaurowa.org" にして更新して無事取得
取得には時間がかかりますけどね〜 さて、どうやってビルドしようか。
最近の端末は、2.2以降もが搭載されているのかな?
まだ、2.1以前はあるのかな
IS01は別として、Xperiaは2.1だったかないずれにせよどこから作るかちょっと悩むが
タブレットが多い昨今、レイアウト系の話を考えると2.2以降が良いのかなと考える。
いろいろと開発案件が乱立していて、こちらに時間を割けませんでしたが少し落ち着いたので。
MediaSwitch系列のバージョンアップ
Bluetooth系の新アプリ
のプロジェクトを開始します。