AndroidWearで円形デバイスだけViewが表示されない

Android Wear Appを作る際にレイアウトを円形と四角でレイアウトを変えたい場合があります。
Android Studioでウィザード形式でActivityを作成すると、下記のファイルができるはずです。

今回はactivity_actionという名前で作成しました

すると3ファイル作成されますよね。

activity_action.xml

 <?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.WatchViewStub
 xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/watch_view_stub"
android:layout_width="match_parent" android:layout_height="match_parent"
app:rectLayout="@layout/rect_activity_action" app:roundLayout="@layout/round_activity_action"
tools:context="com.miruker.qcontact.ActionActivity"
tools:deviceIds="wear"></android.support.wearable.view.WatchViewStub>
rect_activity_action.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:orientation="vertical"
 tools:context="com.miruker.qcontact.ActionActivity" tools:deviceIds="wear_square">

 <android.support.wearable.view.GridViewPager
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/indicatorSize"
 android:visibility="visible"
 android:id="@+id/gridViewPager" />

 <LinearLayout
 android:id="@+id/page_dots_container"
 android:orientation="horizontal"
 android:layout_gravity="bottom|center_horizontal"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

</FrameLayout>
 

round_activity_action.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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" tools:context="com.miruker.qcontact.ActionActivity"
 tools:deviceIds="wear_round">

 <android.support.wearable.view.GridViewPager
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:visibility="visible"
 android:paddingBottom="40dp"
 android:id="@+id/gridViewPager" />

 <LinearLayout
 android:id="@+id/page_dots_container"
 android:orientation="horizontal"
 android:layout_gravity="bottom|center_horizontal"
 android:layout_marginBottom="28dp"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>
</FrameLayout>
でJavaファイルがこちら (一部割愛)

ActionActivity.java
@Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_action);

 //前の画面からデータをもらっています
 mActionType = getIntent().getIntExtra(Global.PARAM.ACTION_TYPE, -1);
 List<String> values = getIntent().getStringArrayListExtra(Global.PARAM.VALUE_LIST);
 List<String> labels = getIntent().getStringArrayListExtra(Global.PARAM.LABEL_LIST);

//リストデータの構築
 for (int i = 0; i < values.size(); i++) {
 mItems.add(new WearContactItem(0, 0, mActionType, labels.get(i), values.get(i), ""));
 }
 mListView = ButterKnife.findById(this,R.id.gridViewPager);
 mIndicator = ButterKnife.findById(this,R.id.page_dots_container);
 mListView.setOnPageChangeListener(new GridViewPager.OnPageChangeListener() {
 @Override
 public void onPageScrolled(int i, int i2, float v, float v2, int i3, int i4) {

 }

 @Override
 public void onPageSelected(int row, int column) {
 setIndicator(column);
 }

 @Override
 public void onPageScrollStateChanged(int i) {

 }
 });

 //GridViewPagerにアダプターをセット
 ActionListAdapter adapter = new ActionListAdapter(getFragmentManager(), mItems, ActionActivity.this, mActionType);
 mListView.setAdapter(adapter);

 //インジケータViewを作成
 mIndicator.removeAllViews();
 for (int i = 0; i < adapter.getColumnCount(0); i++) {
 ImageView v = new ImageView(getApplicationContext());
 v.setImageResource(R.drawable.black_circle);
 mIndicatorList.add(v);
 mIndicator.addView(v);
 }
 インジケータの初期値
 setIndicator(0);

 mGoogleApiClient = new GoogleApiClient
 .Builder(this)
 .addConnectionCallbacks(this)
 .addApi(Wearable.API)
 .build();

 }
まぁちょっと色々端折っているのですが、単純に画面中央にはGridViewPagerがあります。

その下にはインジケータ用にLinearLayout(Horizontal)のViewがあるような感じですね。

GridViewPagerはFragmntを返すようになっています。

期待する動作としてはそのようなもんで、私の所持している G watchでも正常に表示されていましたがどうやら円形デバイスで表示されないという不具合報告を受けました。

その際に表示されている画面はインジケータは表示されているがそれ以外は何も表示されていない。

要はGridViewPagerのFragmentが表示されていないということなんですね。

StackOverFlowにありました。

 

http://stackoverflow.com/questions/25808229/fragment-in-round-wear-watch-turning-black-in-emulator-watch

英語があんまり読めないので大体の解釈なのですが、RoundDeviceだとInflateする際の動きがSquareと少し違うようで、GridViewPagerで内部で管理しているタグが整合性が合わなくなるみたいなのです。

結局シンプルな解決策として、Stubを使わないようにしました。

セールのお知らせ – Quick電話帳

Quick電話帳のAndroid Wearライセンスが現在セールで半額です!

もしよろしければおためしください〜

Quick電話帳Ver13.0を公開しました

グループ内に存在する電話帳の件数を表示できるオプションを追加しました
Android Wearでデフォルト電話番号へアクセスしやすくしました
Android Wearのアイコンサイズを調整しました
50音順で「ろ」が検索に引っかからない不具合を修正しました
その他レイアウトの調整を行いました

Quick電話帳Ver12.1公開しました

デザイン面での細かな調整を行いました。

Quick電話帳Ver12.0を公開しました

変更内容は下記のとおりです。

WearAppでより多くの連絡先情報にアクセスできるようになりました。
Material Designへの対応を実施しました。
一部のレイアウトを調整しています。

Android wearエミュレータ(Round)表示がおかしい件

Mac OS X Yosemite?(前から?)AndroidWearのRound形式でエミュレータ作ると残念なことになります。

スクリーンショット 2014-10-31 7.41.53

いやいや。こういうの期待してないです。

期待している表示はこっちのはずです。
スクリーンショット 2014-10-31 7.42.19

解消方法ですがエミュレータ作成時に、デフォルトチェックされているUse Host GPUのチェックを外しましょう。
スクリーンショット 2014-10-31 7.45.40

YosemiteにしたらAndroid emulatorのx86が起動しない

missing HAXMと言われ起動しなくなりました。

https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager

こちらから最新のHAXMをインストールすることで解消します

Android 5.0のRippleEffectを4.4以下で同じような動きで作ってみた

使う場合はいろいろなものを適正読み替えてくださいー。



public class RippleLinearLayout extends LinearLayoutCompat {

private static final int DURATION = 2000;
private static final int RIPPLE_ALPHA = 150;
private static final int TOUCH_ALPHA = 50;
private static final int ACTIVATE_ALPHA = 150;

@Setter
private float mDownX;
@Setter
private float mDownY;

private float mRadius;

private Paint mPaint;
private boolean mIsActivatedAnimate = false;
private int mColor = Color.BLACK;
private int mActivateAlpha = ACTIVATE_ALPHA;
private int mDuration = DURATION;
private int mRippleAlpha = RIPPLE_ALPHA;

private boolean mPressed = false;
private boolean mActivated = false;
private AnimatorSet mAnimator;


private void init(Context context, AttributeSet attrs) {
mPaint = new Paint();
mPaint.setAlpha(mRippleAlpha);

mColor = getResources().getColor(R.color.ColorGray);

if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
mRippleAlpha = a.getInteger(R.styleable.RippleView_rippleAlpha, RIPPLE_ALPHA);
mIsActivatedAnimate = a.getBoolean(R.styleable.RippleView_isActivateAnimate,false);
mDuration = a.getInteger(R.styleable.RippleView_rippleDuration, DURATION);
a.recycle();
}

}

/**
* コンストラクタ
*
* @param context コンテキスト
*/
public RippleLinearLayout(Context context) {
this(context, null);
setBackgroundResource(R.color.Transparent);
setOnTouchListener(new ontouchListener());
init(context, null);
}

/**
* コンストラクタ2
*
* @param context コンテキスト
* @param attrs アトリビュート
*/
public RippleLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {
setBackgroundResource(R.color.Transparent);
setOnTouchListener(new ontouchListener());
init(context, attrs);
}
}

private class ontouchListener implements OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
case MotionEvent.ACTION_UP:
break;
}
return false;
}
}

/**
* コンストラクタ3
*
* @param context コンテキスト
* @param attrs アトリビュート
*/
public RippleLinearLayout(Context context, AttributeSet attrs, int Defstyle) {
super(context, attrs, Defstyle);
setBackgroundResource(R.color.Transparent);
setOnTouchListener(new ontouchListener());
}

public void setRadius(final float radius) {
mRadius = radius;
if (mRadius > 0) {
RadialGradient radialGradient = new RadialGradient(
mDownX,
mDownY,
mRadius * 3,
mColor,
mColor,
Shader.TileMode.MIRROR
);
mPaint.setAlpha(mRippleAlpha);
mPaint.setShader(radialGradient);
}
invalidate();
}

@Override
public void setPressed(boolean pressed) {

if (pressed != mPressed) {
mPressed = pressed;
if (mPressed) {
mAnimator = new AnimatorSet();
ObjectAnimator animator1 = ObjectAnimator.ofFloat(RippleLinearLayout.this, “radius”, getWidth() / 10.0f, getWidth() * 3.0f);
animator1.setInterpolator(new AccelerateDecelerateInterpolator());
animator1.setDuration(mDuration);
mAnimator.playTogether(animator1);
mAnimator.start();
setBackgroundColor(Color.argb(TOUCH_ALPHA, Color.red(mColor), Color.green(mColor), Color.blue(mColor)));
} else {
if (mAnimator != null)
mAnimator.cancel();
setRadius(0);
// if(!mIsActivatedAnimate && !isActivated())
setBackgroundColor(getResources().getColor(R.color.Transparent));
}
}
if (!pressed) {

}

super.setPressed(pressed);
}

@Override
public void setActivated(boolean activated) {
super.setActivated(activated);

if (mActivated != activated) {
mActivated = activated;
if (activated) {
if (mIsActivatedAnimate)
setBackgroundColor(Color.argb(mActivateAlpha, Color.red(mColor), Color.green(mColor), Color.blue(mColor)));
} else {
setBackgroundColor(getResources().getColor(R.color.Transparent));
}
}
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

canvas.drawCircle(mDownX, mDownY, mRadius, mPaint);

}


}

Quick電話帳 10.2を公開しました

主にアイコン・レイアウトの変更等でマテリアルデザインの要素を取り入れています。

Quick電話帳 Ver10.0を公開しました

下記の機能が更新されています。

ウィジェットの画面が新しくなりました
電話用ショートカットが作成できるようになりました
(これに伴い起動時にダイアラー表示オプションは廃止しました)
カラー選択画面がより使いやすくなりました
アイコンカラーを変更しました
いくつかの不具合を修正しました