On Android Wear devices with a "chin", the screen size is still reported as square, but you get this WindowInsets
object which contains information about what has been cropped from the screen.
I have a config screen which is already correctly fetching this value, easily confirmed because my views render an outline of the screen shape.
public class ConfigView extends FrameLayout {
private Rect lastBounds = new Rect();
private WindowInsets lastWindowInsets;
//... omitting initialisation
@Override
protected void onFinishInflate() {
super.onFinishInflate();
requestApplyInsets();
// omitting other stuff not relevant to this
GridViewPager pager =
(GridViewPager) findViewById(R.id.pager);
DotsPageIndicator dotsPageIndicator =
(DotsPageIndicator) findViewById(R.id.page_indicator);
dotsPageIndicator.setPager(pager);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
WindowInsets result = super.onApplyWindowInsets(insets);
lastWindowInsets = insets;
maybeInitialiseViews();
return result;
}
@Override
protected void onLayout(boolean changed, int left, int top,
int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
lastBounds.set(left, top, right, bottom);
maybeInitialiseViews();
}
private void maybeInitialiseViews() {
if (lastWindowInsets != null && !lastBounds.isEmpty()) {
GridViewPager pager =
(GridViewPager) findViewById(R.id.pager);
if (pager.getAdapter() == null) {
// TODO: Maybe there is a better callback I can rely on
// being done on every layout but not before applying
// insets, but a failure occurs later if we initialise
// the adapter before we have both bits of info.
pager.setAdapter(new ConfigGridPagerAdapter());
}
}
}
}
My problem is now the positioning of the components. The layout XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<example.ConfigView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.wearable.view.GridViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
android:nestedScrollingEnabled="false"/>
<android.support.wearable.view.DotsPageIndicator
android:id="@+id/page_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
app:dotFadeWhenIdle="false"/>
</example.ConfigView>
</android.support.wearable.view.BoxInsetLayout>
Though the screen is truncated by the chin, the system has given the ConfigView
the entire 320x320 space. This puts the bottom of the list as well as the page indicator off the bottom of the screen. I tried using padding to move them back up manually, but padding appeared to have no effect and I'm not quite sure why.
I have also tried making Config
itself a BoxInsetLayout
and messing with which side gets the insets, but that doesn't appear to change anything visually.
I tried putting app:layout="bottom"
on the ConfigView
in the XML, which does make it work for the chin layout, but then adds an unwanted border when there is no chin.
How is this supposed to work? It bugs me a bit that this doesn't just work. When I'm programming on a 1920x1080 monitor, I don't have to do anything special to crop down a 1920x1920 box.
I was also looking to pad the bottom of my layout to factor in the size of the chin. I managed to do this by wrapping everything in a customised FrameLayout and setting the padding in onApplyWindowInsets()
.
public class ChinLayout extends FrameLayout {
public ChinLayout(Context context) {
super(context);
}
public ChinLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ChinLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ChinLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int chin = insets.getSystemWindowInsetBottom();
setPadding(0, 0, 0, chin);
return insets;
}
}
Then I used ChinLayout
at the root of my hierarchy:
<?xml version="1.0" encoding="utf-8"?>
<ChinLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- View hierarchy to fit above the chin goes here. -->
</ChinLayout>
The correct way to compensate for the chin is explained in the Android documentation .
You do not need a custom layout anymore, instead use the fitsSystemWindow
attribute on the root layout to have the padding automatically adjusted.
Forewarned, this technique does not work if your root layout is a RelativeLayout
in which case you need to replace it or wrap it in a FrameLayout
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.