Android FloatingSearchView inside Toolbar - google-play

Hi i have a specific question.
Im using the library floatingsearchview (https://github.com/arimorty/floatingsearchview) in my Project.
I try implementing a google play store like Toolbar using the design support library (AppBarLayout/Toolbar that collapses when scrolling).
The Searchview is inside the Toolbar and the scrolling and disappearing works flawless (when height is set to match toolbar height). Nevertheless the searchview needs to be set to height:match_parent when you want to display any results under the searchview which will expand the Toolbar to fill the whole screen...
Any opinions on how doing so ?
This is how it works in Google Play (but you should be able to test it in your Google Play store App too)

From the author of the library.
The View's height determines the height if that the suggestions will have. Meaning, you can set any height for the View, but it won't look good if it's less than the full height because the suggestions won't expand to the entire screen's height.
So, no, it is impossible to use it within the Toolbar.

I managed to get this working by using a FrameLayout like this:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
layout="#layout/toolbar" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
style="#style/AppTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<com.arlib.floatingsearchview.FloatingSearchView
android:id="#+id/floating_search_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
background="#5E5C62"
app:floatingSearch_searchBarMarginLeft="8dp"
app:floatingSearch_searchBarMarginRight="8dp"
app:floatingSearch_showMenuAction="true"
app:floatingSearch_searchHint="Search…"
app:floatingSearch_showSearchHintWhenNotFocused="true"
app:floatingSearch_showVoiceInput="false"
app:floatingSearch_showOverFlowMenu="false"
app:floatingSearch_hideOverflowMenuWhenFocused="false"
app:floatingSearch_showSearchKey="false"
app:floatingSearch_dismissOnOutsideTouch="true" />
</FrameLayout>
This might not be the best setup but it works for me and shows suggestions properly.

For me thats worked, edit your resources xml and add a new custom Behavior for the FloatingSearchView
activity.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.HomeActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="70dp"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/searchContainer"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.arlib.floatingsearchview.FloatingSearchView
android:id="#+id/floating_search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:floatingSearch_close_search_on_keyboard_dismiss="true"
app:floatingSearch_leftActionMode="showHome"
app:floatingSearch_menu="#menu/menu_search"
app:floatingSearch_searchBarMarginLeft="#dimen/search_view_inset"
app:layout_behavior="com.example.utils.SearchBehavior"
app:floatingSearch_searchBarMarginRight="#dimen/search_view_inset"
app:floatingSearch_searchBarMarginTop="5dp"
app:floatingSearch_searchHint="Search..."
app:floatingSearch_showSearchKey="true"
app:floatingSearch_suggestionsListAnimDuration="250" />
</android.support.design.widget.CoordinatorLayout>
Then create your custom class mentioned into attribute app:layout_behavior of FloatingSearchView tag :
public class SearchBehavior extends
CoordinatorLayout.Behavior<FloatingSearchView> {
private AppBarLayout mAppBarLayout;
private android.support.design.widget.AppBarLayout.Behavior
mAppBarLayoutBehavior;
private ValueAnimator mValueAnimator;
private FloatingSearchView mSearchView;
private boolean isScrolling;
public SearchBehavior() {
}
public SearchBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean layoutDependsOn(CoordinatorLayout parent,
FloatingSearchView child, View dependency) {
if (dependency instanceof AppBarLayout) {
this.mSearchView = child;
this.mAppBarLayout = (AppBarLayout) dependency;
CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) this.mAppBarLayout.getLayoutParams();
if (Build.VERSION.SDK_INT >= 21) {
this.mAppBarLayout.setStateListAnimator((StateListAnimator)
null);
}
this.mAppBarLayoutBehavior =
(android.support.design.widget.AppBarLayout.Behavior)
params.getBehavior();
return true;
} else {
return super.layoutDependsOn(parent, child, dependency);
}
}
public boolean onDependentViewChanged(CoordinatorLayout parent,
FloatingSearchView child, View dependency) {
if (dependency instanceof AppBarLayout) {
this.mSearchView.setTranslationY(dependency.getY());
return true;
} else {
return super.onDependentViewChanged(parent, child, dependency);
}
}
public void onNestedPreScroll(CoordinatorLayout parent,
FloatingSearchView child, View target, int dx, int dy, int[] consumed)
{
if (dy < 0 && dy <= -10 && !this.isScrolling) {
this.isScrolling = true;
if (this.needsToAdjustSearchBar() &&
!this.isRunningAnimation()) {
int offset = this.getMinExpandHeight();
this.getValueAnimator(parent, child, -offset).start();
}
}
}
public void onNestedScroll(CoordinatorLayout coordinatorLayout,
FloatingSearchView child, View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed,
dyConsumed, dxUnconsumed, dyUnconsumed);
}
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout,
FloatingSearchView child, View target) {
this.isScrolling = false;
}
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
FloatingSearchView child, View directTargetChild, View target, int
nestedScrollAxes) {
return nestedScrollAxes == 2 ||
super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,
target, nestedScrollAxes);
}
private int getStatusBarHeight() {
if (Build.VERSION.SDK_INT > 19) {
return 0;
} else {
int result = 0;
int resourceId = this.mSearchView.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = this.mSearchView.getContext().getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}
private ValueAnimator getValueAnimator(CoordinatorLayout parent, FloatingSearchView searchView, int offset) {
if (this.mValueAnimator == null) {
this.mValueAnimator = ValueAnimator.ofInt(new int[0]);
} else if (this.mValueAnimator.isRunning()) {
return this.mValueAnimator;
}
this.mValueAnimator.setInterpolator(new DecelerateInterpolator());
this.mValueAnimator.setIntValues(new int[]{this.mAppBarLayoutBehavior.getTopAndBottomOffset(), offset});
return this.mValueAnimator;
}
private boolean isRunningAnimation() {
return this.mValueAnimator != null && this.mValueAnimator.isRunning();
}
private boolean needsToAdjustSearchBar() {
float y = (float) Math.abs(this.mAppBarLayoutBehavior.getTopAndBottomOffset());
return y > (float) this.getMinExpandHeight();
}
private int getMinExpandHeight() {
return Build.VERSION.SDK_INT >= 16 ?
this.mAppBarLayout.getTotalScrollRange() -
this.mSearchView.getMinimumHeight() - this.getStatusBarHeight() / 2 :
this.mAppBarLayout.getTotalScrollRange() - this.mSearchView.getHeight() -
this.getStatusBarHeight() / 2;
}
}

Related

How can i use Xamarin.Forms ContentView in xamarin Android Main.xml

I create a ContentView in xamarin forms and i want to use it in Main.xml in the xamarin android
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SwapPage : ContentView
{
public SwapPage()
{
InitializeComponent();
}
double? layoutHeight;
double layoutBoundsHeight;
int direction;
const double layoutPropHeightMax = 0.75;
const double layoutPropHeightMin = 0.04;
private void PanGestureHandler(object sender, PanUpdatedEventArgs e)
{
layoutHeight = layoutHeight ?? ((sender as StackLayout).Parent as AbsoluteLayout).Height;
switch (e.StatusType)
{
case GestureStatus.Started:
layoutBoundsHeight = AbsoluteLayout.GetLayoutBounds(sender as StackLayout).Height;
break;
case GestureStatus.Running:
direction = e.TotalY < 0 ? 1 : -1;
var yProp = layoutBoundsHeight + (-e.TotalY / (double)layoutHeight);
if ((yProp > layoutPropHeightMin) & (yProp < layoutPropHeightMax))
AbsoluteLayout.SetLayoutBounds(bottomDrawer, new Rectangle(0.5, 1.00, 0.9, yProp));
break;
case GestureStatus.Completed:
if (direction > 0) // snap to max/min, you could use an animation....
{
AbsoluteLayout.SetLayoutBounds(bottomDrawer, new Rectangle(0.5, 1.00, 0.9, layoutPropHeightMax));
swipeLabel.Text = "Swipe me down";
}
else
{
AbsoluteLayout.SetLayoutBounds(bottomDrawer, new Rectangle(0.5, 1.00, 0.9, layoutPropHeightMin));
swipeLabel.Text = "Swipe me up";
}
break;
}
}
}
This is my ContentView and
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:weightSum="100"
xmlns:local="clr-namespace:......Pages">
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="0dp"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_weight="90"/>
<local:SwapPage
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
and the error is
Android.Views.InflateException: 'Binary XML file line #1: Binary XML file line #1: Error inflating class SwapPage'

Bizzare behavior of NotifyDataSetChanged() Xamarin.Android

I am working on an application that asks the user to provide photos for items.
My main object is following
public class PickedObject
{
int ID { get; set; }
int Name{ get; set; }
bool HasPhotos { get; set; }
}
And I have another table for Photos since one item can have multiple photos.
What's happening is that in my adapter, I have created a recycler view so that if an Item has images, there should be an ImageButton visible in front of it.
Here is my row template
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="8">
<TextView
android:id="#+id/lblItemName"
android:layout_width="0dp"
android:layout_weight="6"
android:layout_marginTop="5dp"
android:layout_marginLeft="10dp"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="" />
<ImageButton
android:layout_weight="1"
android:layout_width="35dp"
android:layout_height="35dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_marginTop="5dp"
android:background="#android:color/transparent"
android:padding="5dp"
android:src="#drawable/rowcamera"
android:id="#+id/btnCamera" />
<ImageButton
android:layout_weight="1"
android:layout_width="35dp"
android:layout_height="35dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_marginTop="5dp"
android:background="#android:color/transparent"
android:padding="5dp"
android:src="#drawable/rowpicture"
android:id="#+id/btnPicture" />
</LinearLayout>
In my adapter I am using the following in GetView(int position, View convertView, ViewGroup parent)
public override View GetView(int position, View convertView, ViewGroup parent)
{
ItemViewHolder holder = null;
PickedObject item = _items[position];
View view = convertView;
try
{
if (view != null)
holder = (ItemViewHolder)view.Tag; //Holder
if(holder == null)
{
holder = new ItemViewHolder();
view = _context.LayoutInflater.Inflate(Resource.Layout.ItemRow, null);
holder.ItemName = view.FindViewById<TextView>(Resource.Id.lblItemName);
holder.CameraButton = view.FindViewById<ImageButton>(Resource.Id.btnCamera);
holder.CameraButton.Tag = item.ID;
holder.PictureButton = view.FindViewById<ImageButton>(Resource.Id.btnPicture);
holder.PictureButton.Tag = item.ID;
CameraClickListener cameraListener = new CameraClickListener(_context, this);
cameraListener.CameraClickEvent += CameraClickedEvent;
holder.CameraButton.SetOnClickListener(cameraListener);
ImageClickListener imageClickListener = new ImageClickListener(_context);
imageClickListener.ImageClickEvent += ImageClickedEvent;
holder.PictureButton.SetOnClickListener(imageClickListener);
view.Tag = holder;
}
holder.ItemName.Text = item.Name;
holder.CameraButton.Visibility = ViewStates.Visible;
if (item.HasPhotos)
{
holder.PictureButton.Visibility = ViewStates.Invisible;
}
else
{
holder.PictureButton.Visibility = ViewStates.Visible;
}
}
catch(Exception ex)
{
Log.Error("Item adapter", ex.Message);
}
return view;
}
Now in my MainActivity I have called two activities (for result), One is the camera activity that starts the camera and saves the photo.
The other activity is a gallery type activity that is created within the project.
The activity on result is called as follows:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
int itemId = CameraApp.ID; // Camera App is a static object to hold data
if (requestCode == General.CAMERA_ACTIVITY) // Camera activity code 110
{
CompleteCameraActivity(resultCode, data); // Save picture into gallery and update db
}
if(requestCode == General.GALLERY_ACTIVITY) // Gallery activity code 113
{
CompleteGalleryActivity(resultCode, data);
}
SectionFragment frag = (SectionFragment)sectionsAdapter.GetItem(viewPager.CurrentItem);
int sectionId = frag.Section.ID;
frag.Adapter.SetPicture(questionId, dataAccess.HasPictures(itemId));
}
The SetPicture method in the adapter is as follows:
public void SetPicture(int id, bool hasPics)
{
Item itm = _items.SingleOrDefault(a => a.ID == id);
if (itm != null)
_items.SingleOrDefault(a => a.ID == id).HasPhotos = hasPics;
this.NotifyDataSetChanged();
}
The application works fine when it comes from Camera activity. It updates the record and also the image button is visible as well.
The trouble comes when the MainActivity gains control after GalleryActivity. When I delete all the images in the gallery the SetPicture method is executed which makes the HasPhotos property to false. But the NotifyDataSetChanged part of the adapter doesn't work (when I test it in debugger the GetView method is not fired for the adapter).
So what happens is that my ListView remains in a state where even if the item has no photos the ImageButton (for pictures) is still available.
Can someone please let me know what I am doing wrong?
EDIT
I noticed that if I scroll the list once and return back to the item, the ImageButton is invisible, that means that it is working but why doesn't it work in StartActivityForResult?

How to change MvxDialogFragment layout

I want to change the default AlertDialog layout size.
I created class:
public class SampleDialog : MvxDialogFragment
{
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
var dialog = new AlertDialog.Builder(Context);
dialog.SetView(View.Inflate(Context,Resource.Layout.SampleDialog,null));
return dialog.Create();
}
public override void OnStart()
{
if (Dialog == null) { return; }
Dialog.Window.SetLayout(200,460);
base.OnStart();
}
}
and it's layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/text1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/text2" />
</LinearLayout>
And i'm creating dialog from fragment view:
var dialog = new SampleDialog
{
ViewModel = ViewModel,
Cancelable = true
};
dialog.Show(FragmentManager, "");
Tryed to set layout width in OnCreateDialog method,OnStart, or directly by setting LinearLayout.layout_width property, but the result is the same.
How this can be configured?
Inflating the layout
When inflating the layout you can make use of either the default inflator or Mvvmcross BindingInflate which will apply any xml bindings you require.
Default inflator:
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
base.EnsureBindingContextSet(savedInstanceState);
var dialog = new AlertDialog.Builder(Context);
dialog.SetView(Activity.LayoutInflater.Inflate(Resource.Layout.SampleDialog, null));
return dialog.Create();
}
Mvvmcross xml binding inflator:
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
base.EnsureBindingContextSet(savedInstanceState);
var dialog = new AlertDialog.Builder(Context);
dialog.SetView(this.BindingInflate(Resource.Layout.SampleDialog, null));
return dialog.Create();
}
Sizing the layout
The Dialog.Window.SetLayout() takes in the pixel values for 200(width) and 460(height) which will vary in physical size with different device screen resolutions.
A better approach would be to use dp and convert it to pixels:
Add the desired size dimensions to your dimens.xml
<resources>
<dimen name="dialog_width">400dp</dimen>
<dimen name="dialog_height">200dp</dimen>
</resources>
Update your SampleDialog
public override void OnStart()
{
base.OnStart();
var width = Resources.GetDimension(Resource.Dimension.dialog_width);
var height = Resources.GetDimension(Resource.Dimension.dialog_height);
Dialog.Window.SetLayout((int)width, (int)height);
}

Xamarin MVVMCross - Binding on a Google Maps InfoWindow

I´m trying to use MvvmCross binding inside a Google Maps InfoWindow, on Android. I have a MvxFragment with a MapFragment inside.
I created a custom xml layout for the InfoWindow and tried to use a MvxFrameControl to display it, like this:
public class InfoWindow : Java.Lang.Object, GoogleMap.IInfoWindowAdapter
{
private readonly BaseStateFragment _window;
private readonly Dictionary<string, Restaurant> _restaurants;
public InfoWindow(BaseStateFragment window, Dictionary<string, Restaurant> restaurants)
{
_window = window;
_restaurants = restaurants;
}
public View GetInfoContents(Marker p0)
{
var layoutContainer = new MvxFrameControl(Resource.Layout.fragment_home_map_info, _window.Context, null)
{
LayoutParameters = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent),
DataContext = _restaurants[p0.Id] //ViewModel
};
return layoutContainer;
}
public View GetInfoWindow(Marker p0)
{
return null;
}
When I click on the marker, the method GetInfoContents is called but nothing is happening (the event binding is ok, I got it to work without binding).
Any ideas ?
As Requested, the layout file:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<include
android:id="#+id/restaurant_item"
android:layout_width="310dp"
android:layout_height="190dp"
layout="#layout/item_list_restaurant" />
<Button
android:id="#+id/bt_open_restaurant"
android:layout_width="310dp"
android:layout_height="wrap_content"
android:text="#string/label_go_restaurant_page"
android:textColor="#color/colorFacebook"
android:background="#color/lightBlue"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:layout_gravity="bottom"
android:layout_marginTop="8dp"
android:textAllCaps="true"
android:layout_marginBottom="4dp" />
</FrameLayout>

DPad Nav Preference Screen Google TV

I have preferences created from XML and preferenceFragment and left-hand navigation. When I choose "Settings" my pref fragments comes out...I can use DPad to move up and down, when there are no more choices on the bottom, the cursor stops (desired behavior), but when I move up the list, the cursor continues over to the left-hand nav. I want it to stop at the top. Below is my pref_screen xml. My left hand nav is created code side. I have no idea how to work DPad logic into this. I also want to restrict the DPad from moving cursor over to left-hand navigation menu if in settings fragment.
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="main_pref">
<PreferenceCategory
android:title="#string/units">
<ListPreference
android:key="pref_unit_temp"
android:title="#string/temperature"
android:defaultValue="#string/default_metric"
android:entries="#array/pref_temp_units"
android:entryValues="#array/pref_temp_units_values"
android:dialogTitle="#string/units"
android:layout="#layout/settings_item" />
</PreferenceCategory>
<PreferenceCategory
android:title="#string/advanced">
<ListPreference
android:key="pref_speed"
android:title="#string/speed"
android:entries="#array/pref_speed"
android:entryValues="#array/pref_speed_values"
android:defaultValue="#string/default_metric"
android:layout="#layout/settings_item"/>
<ListPreference
android:key="pref_measurement"
android:title="#string/measurement"
android:entries="#array/pref_measurement"
android:entryValues="#array/pref_measurement_values"
android:defaultValue="#string/default_metric"
android:layout="#layout/settings_item"/>
<ListPreference
android:key="pref_time"
android:title="#string/time_format"
android:entries="#array/pref_time"
android:entryValues="#array/pref_time_values"
android:defaultValue="#string/default_metric"
android:layout="#layout/settings_item"/>
<ListPreference
android:key="pref_date"
android:title="#string/date_format"
android:entries="#array/pref_date"
android:entryValues="#array/pref_date_values"
android:defaultValue="#string/default_metric"
android:layout="#layout/settings_item"/>
</PreferenceCategory><!--
<PreferenceCategory
android:title="Weather Notification Bar">
<CheckBoxPreference
android:key="pref_notification_enable"
android:title="Enable Notifications"
android:summary="Turn on/off status bar weather notifications"
android:defaultValue="true"
android:enabled="false"/>
<ListPreference
android:key="pref_notification_update_method"
android:dependency="pref_notification_enable"
android:title="Choose notification update method"
android:summary="Manual, Automatic, Interval"
android:entries="#array/pref_notification_update_method"
android:entryValues="#array/pref_notification_update_method_values"
android:dialogTitle="Update Method" />
<ListPreference
android:key="pref_notification_interval"
android:title="Interval to update"
android:dependency="pref_notification_enable"
android:summary="Use this to set the update interval if interval method is selected"
android:entries="#array/pref_notification_interval"
android:entryValues="#array/pref_notification_interval_values"
android:dialogTitle="Update Interval" />
</PreferenceCategory>
-->
<!--<PreferenceCategory
android:title="Background">
<CheckBoxPreference
android:key="background_enabled"
android:title="Enable Interactive Background"
android:summary="Turn off to improve performance"
android:defaultValue="true"
android:enabled="true"/>
</PreferenceCategory>
--><PreferenceCategory
android:title="AccuWeather">
<!-- <PreferenceScreen
android:title="#string/call_us"
android:summary=""
android:layout="#layout/settings_item">
<intent android:action="android.intent.action.DIAL"
android:data="tel:8142358650" />
</PreferenceScreen>
<PreferenceScreen
android:title="#string/email_us"
android:summary="customerservice#accuweather.com"
android:layout="#layout/settings_item">
<intent android:action="com.accuweather.android.tablet.EMAIL_ACCUWX"
/>
<intent android:action="android.intent.action.SENDTO"
android:data="customerservice#accuweather.com"/>
</PreferenceScreen> -->
<PreferenceScreen
android:title="#string/terms_conditions"
android:summary=""
android:layout="#layout/settings_item">
<intent android:action="android.intent.action.VIEW"
android:data="http://www.accuweather.com/m/EULA.aspx" />
</PreferenceScreen>
</PreferenceCategory>
</PreferenceScreen>
Here is a screen shot:
I had to figure out a way to depict the positions and children to handle dpad. Here is the code I wrote to handle this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
View v = inflater.inflate(R.layout.settings_tile, null);
final ImageView closeBtn = (ImageView) v.findViewById(R.id.settingsCloseButton);
closeBtn.setFocusable(true);
closeBtn.setOnClickListener(this);
closeBtn.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
v.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
return false;
}
if (event.getAction() == KeyEvent.ACTION_DOWN) {
return !(KeyEvent.KEYCODE_DPAD_DOWN == keyCode);
}
return false;
}
});
} else {
v.setOnKeyListener(null);
}
}
});
final ListView lv = (ListView) v.findViewById(android.R.id.list);
lv.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch(keyCode) {
case KeyEvent.KEYCODE_DPAD_DOWN:
return !(lv.getSelectedItemPosition() < lv.getCount() - 1);
case KeyEvent.KEYCODE_DPAD_UP:
if (lv.getSelectedItemPosition() == 1) {
closeBtn.requestFocus();
}
return lv.getSelectedItemPosition() == 1;
case KeyEvent.KEYCODE_DPAD_RIGHT:
return true;
}
return false;
}
return false;
}
});
consumeKeyEvent(v);
return v;
}
private void consumeKeyEvent(Object obj) {
if (obj instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup)obj).getChildCount(); i++) {
consumeKeyEvent(((ViewGroup)obj).getChildAt(i));
}
return;
}
((View)obj).setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
Log.i(DEBUG_TAG, "Event consumed, " + keyCode);
return false;
}
});
}

Resources