How to highlight selected list item in android? - android-listview

In my android application i have list view and detail view for each list item. For tablets i have shown list view of items and selected item's detail view as follows.
So my problem is how can i highlight the selected item after user clicks on list item.
I am using a BaseAdapter to load list view.How can i do this any idea??
EDIT:
Yes as chintan khetiya mentioned i have used following xml file as the background of list item but it will not delighted the selected item. What have i missed?
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="false"
android:state_pressed="false"
android:drawable="#color/abs__background_holo_light" />
<item android:state_pressed="true"
android:drawable="#color/action_bar_blue" />
<item android:state_selected="true"
android:state_pressed="false"
android:drawable="#color/action_bar_blue" />
</selector>

Your Query :
my problem is how can i highlight the selected item after user clicks on list item.
I think you are asking about selector. Mean if the list row in focus state then it should be look different form all other row. Same thing when you press or Touch the Row.
For that you have to make Selector.xml File in Drawable folder and just put that selector file in your list row
That file should have different tag like Focus-Click-Press and change the Drawable as per state.
Update :
Just Replace Your icon and save in Drawable folder.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Pressed -->
<item android:drawable="#drawable/p_paly_press" android:state_pressed="true"/>
<!-- selected -->
<item android:drawable="#drawable/p_play" android:state_selected="true"/>
<!-- focused -->
<item android:drawable="#drawable/p_paly_press" android:state_focused="true"/>
<!-- default -->
<item android:drawable="#drawable/p_play"/>
</selector>

The code similar to the following code below can be used to highlight the selected item for sure if other ways do not do that you need:
class Adapter extends ArrayAdapter<String> {
private int selectedPos = -1;
Drawable selectedBackground;
public MainSelectAdapter(Context context, int textViewResourceId,
List<String> objects) {
super(context, textViewResourceId, objects);
selectedBackground =
context.getResources().getDrawable(R.color.selecteditembackground);
}
public void setSelectedPosition(int pos){
selectedPos = pos;
notifyDataSetChanged();
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
if (selectedPos == position) {
v.setBackgroundDrawable(selectedBackground);
} else {
v.setBackgroundDrawable(null);
}
return v;
}
}
And the in the main activity
Adapter adapter = new Adapter(this, android.R.layout.simple_list_item_1,
myItemsToShow);
list = (ListView) findViewById(R.id.flows);
list.setItemsCanFocus(true);
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapter, View view,
int pos, long id) {
adapter.setSelectedPosition(pos);
}
});
With this approach, you take own control on the selected item highlighting, you have a listener to capture selection events and you set yourself the required Drawable.

You can define in your styles.xml
<style name="Theme.Base" parent="...">
<item name="activatableItemBackground">#drawable/activatable_item_background</item>
</style>
<style name="ListItemContainerBase">
<item name="android:background">?activatableItemBackground</item>
</style>
In res/drawable define activatable_item_background.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/item_pressed" android:state_pressed="true" />
<item android:drawable="#drawable/item_focused" android:state_focused="true" />
<item android:drawable="#drawable/item_focused" android:state_selected="true" />
<item android:drawable="#drawable/item_activated" android:state_activated="true" />
<item android:drawable="#drawable/item_checked" android:state_checked="true" />
<item android:drawable="#android:color/transparent" />
</selector>
item_pressed, item_focused..... are images in res/drawable-xxx
Define for each items in your view a layout like this:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/ListItemContainerBase">

Related

Prevent a Border control from shrinking when its child controls shrink

I have a Border control that contains a couple of Label controls. The text shown in the labels changes, and this causes the Border control to expand and shrink horizontally. To prevent flickering, I want it to be able to expand but not shrink. Is there a way to do this?
Alternatively, is there a way to specify that the Label objects should expand horizontally but never shrink - which would give the same outcome?
My XAML is:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="uk.andyjohnson.TakeoutExtractor.Gui.ProgressOverlay">
<Border
Stroke="#0f0f0f"
StrokeThickness="2"
StrokeShape="RoundRectangle 5,5,5,5"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Padding="30,30">
<VerticalStackLayout
Spacing="25" >
<Label
x:Name="SourceLabel"
Text=""
HorizontalOptions="Center"/>
<Label
x:Name="DestinationLabel"
Text=""
HorizontalOptions="Center" />
</VerticalStackLayout>
</Border>
</ContentView>
Thanks!
You could play with labels WidthRequest.
When your label increase in size, you set its WidthRequest to its current Width value.
Assuming for simplicity that you're changing the label text in your code-behind and that there is only one label, something like this should do the job.
public partial class ProgressOverlay
{
private double currentWidth = 0;
// I create this method just to explain.
// It could be anything in your code that changes your label text
void ChangingText()
{
// ******
// .... SourceLabel text changes here ...
// *******
if (SourceLabel.Width > currentWidth)
{
SourceLabel.WidthRequest = SourceLabel.Width;
currentWidth = SourceLabel.Width;
}
}
}
I solved the problem using a variation on Riccardo Minato's suggestion.
Hook into the SizeChanged event on the bounding Border object.
Track its maximum width using a member variable
When the width exceeds the previous maximum, set the Border object's MinimumWidthRequest property to the new maximum width. This stops it shrinking.
New XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="uk.andyjohnson.TakeoutExtractor.Gui.ProgressOverlay">
<Border
Stroke="#0f0f0f"
StrokeThickness="2"
StrokeShape="RoundRectangle 5,5,5,5"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Padding="30,30"
SizeChanged="Border_SizeChanged"> <!-- ** Added this line ** -->
<VerticalStackLayout
Spacing="25" >
<ActivityIndicator
IsVisible="true"
IsRunning="true"
IsEnabled="true"
HorizontalOptions="Center"/>
<Button
x:Name="CancelButton"
Text="Cancel"
HorizontalOptions="Center"
Clicked="OnCancelButtonClicked"/>
<Label
x:Name="SourceLabel"
Text=""
HorizontalOptions="Center"/>
<Label
x:Name="DestinationLabel"
Text=""
HorizontalOptions="Center"/>
</VerticalStackLayout>
</Border>
</ContentView>
New code-behind:
private double currentMaxWidth = 0D;
private void Border_SizeChanged(object sender, EventArgs e)
{
var bdr = sender as Border;
if (bdr.Width > currentMaxWidth)
{
currentMaxWidth = bdr.Width;
bdr.MinimumWidthRequest = currentMaxWidth;
}
}

.Net MAUI data binding not carrying through to custom component

I am having trouble getting data binding to work with custom components.
I have created an IncrementValue property that gets incremented with every button click.
The changes are reflected when binded to a Label.
However they do not work when I bind it to a Bindable property in a custom component.
In the example, I have built a custom component called Card which has two bindable properties CardTitle and CardIncrement
Is there something I'm missing as I'm new to MAUI and even Xamarin.
Github link of code snippets below: https://github.com/814k31/DataBindingExample
Card.xaml.cs
namespace DataBindingExample;
public partial class Card : VerticalStackLayout
{
public static readonly BindableProperty CardTitleProperty = BindableProperty.Create(nameof(CardTitle), typeof(string), typeof(Card), string.Empty);
public static readonly BindableProperty CardIncrementProperty = BindableProperty.Create(nameof(CardIncrement), typeof(int), typeof(Card), 0);
public string CardTitle
{
get => (string)GetValue(CardTitleProperty);
set => SetValue(CardTitleProperty, value);
}
public int CardIncrement
{
get => (int)GetValue(CardIncrementProperty);
set => SetValue(CardIncrementProperty, value);
}
public Card()
{
InitializeComponent();
BindingContext = this;
}
}
Card.xaml
<?xml version="1.0" encoding="utf-8" ?>
<VerticalStackLayout
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:databindingexample="clr-namespace:DataBindingExample"
x:DataType="databindingexample:Card"
x:Class="DataBindingExample.Card"
Spacing="25"
Padding="30,0"
VerticalOptions="Center"
BackgroundColor="red"
>
<Label
Text="{Binding CardTitle}"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center"
/>
<Label
Text="{Binding CardIncrement}"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center"
/>
</VerticalStackLayout>
MainPage.xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingExample.MainPage"
xmlns:DataBindingExample="clr-namespace:DataBindingExample"
xmlns:ViewModels="clr-namespace:DataBindingExample.ViewModels"
x:DataType="ViewModels:MainPageViewModel"
>
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center"
>
<Label
Text="{Binding IncrementedValue}"
SemanticProperties.HeadingLevel="Level2"
FontSize="18"
HorizontalOptions="Center"
/>
<!-- Why doesnt this work? -->
<DataBindingExample:Card CardIncrement="{Binding IncrementedValue}" />
<Button
x:Name="CounterBtn"
Text="Click Me"
SemanticProperties.Hint="Counts the number of times you click"
Command="{Binding IncrementValueCommand}"
HorizontalOptions="Center"
/>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
When making a custom component (that includes XAML), DO NOT set BindingContext = this;.
REASON: You want the component to use the SAME BindingContext as the page it is placed in. This happens automatically, if you do NOT set a BindingContext in the custom component.
HOWEVER, removing this line breaks all your component's xaml Bindings; you'll need to add something to the xaml, to fix this.
Or to put it another way: How refer to the card's Properties from its XAML? See the next section.
ACCESS COMPONENT PROPERTIES VIA x:Name
Solution: Give the card an x:Name, and make that the "Source" of those bindings:
<VerticalStackLayout
...
x:Name="me" <-- IMPORTANT! Change name as desired.
x:Class="DataBindingExample.Card"
>
...
<Label Text={Binding CardIncrement, Source={x:Reference me}}"
...
Notice the two parts to this solution:
In component's xaml header, define x:Name="mynamehere".
In each Binding, say that the component is the source:
, Source={x:Reference mynamehere}.
OPTIONAL: If custom component has a "ViewModel":
To have a custom component be "data-driven", pass in a parameter that controls its behavior.
This parameter could be considered a "ViewModel", but above I have specified:
DO NOT set a BindingContext (so that component has easy access to the page's BindingContext).
So unlike other uses of ViewModel, in this technique, we don't set the ViewModel as the BindingContext.
How access this ViewModel?
By saving it as a property of the component; e.g.:
public partial class MyComponent : ContentView
{
private MyViewModel VM;
public void MyComponent(MyViewModel vm)
{
InitializeComponent();
VM = vm;
}
public class MyViewModel : ObservableObject
{
[ObservableProperty]
SomeType someProperty; // This is field. Property "SomeProperty" is generated.
}
Then in xaml, we access properties of VM, using . notation:
<Label Text={Binding VM.SomeProperty, Source={x:Reference me}}"

Magento 2 Checkout - dynamically populated dropdown in shippment method section

I am programming a custom shipping method (store pickup).
I added an additional Dropdown Menu with this tutorial: https://zanetabaran.com/how-to-in-magento-2-how-to-add-additional-dropdown-with-options-based-on-selected-shipping-methods-in-the-checkout/
The Values from the dropdown are static at the moment, coming from a js-File from my module->
Pastebin
updateDropdownValues: function(method) {
var valuesCollection = [];
if(method['carrier_code'] == 'customshipping'){
valuesCollection = [
{
label: 'Store1',
value: 'Store1'
},
{
label: 'Store2',
value: 'Store2'
},
{
label: 'Store3',
value: 'Store3'
}
];
} else {
valuesCollection = [];
}
self.updateDropdown(valuesCollection);
},
The dropdown is defined in checkout_index_index.xml -> Pastebin
<item name="shippingAdditional" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
<item name="displayArea" xsi:type="string">shippingAdditional</item>
<item name="children" xsi:type="array">
<item name="shipping-option-wrapper" xsi:type="array">
<!-- Component Magento_Checkout/js/view/additional-shipping-option is used as a wrapper for content -->
<item name="component" xsi:type="string">XXX_CustomShipping/js/view/additional-shipping-option</item>
<item name="provider" xsi:type="string">checkoutProvider</item>
<item name="sortOrder" xsi:type="string">0</item>
<item name="children" xsi:type="array">
<item name="shipping-option" xsi:type="array">
<!-- uiComponent is used as a wrapper for select (its template will render all children as a list) -->
<item name="component" xsi:type="string">uiComponent</item>
<!-- the following display area is used in template -->
<item name="displayArea" xsi:type="string">additionalShippingOptionField</item>
<item name="children" xsi:type="array">
<item name="markt" xsi:type="array">
<item name="component" xsi:type="string">XXX_CustomShipping/js/view/shipping-option-select</item>
<item name="config" xsi:type="array">
<!--customScope is used to group elements within a single form (e.g. they can be validated separately)-->
<item name="customScope" xsi:type="string">shippingOptionSelect</item>
<item name="template" xsi:type="string">ui/form/field</item>
<item name="elementTmpl" xsi:type="string">ui/form/element/select</item>
</item>
<item name="dataScope" xsi:type="string">shippingOptionSelect.select_data</item>
<item name="label" xsi:type="string" translate="true">Please choose a market</item>
<item name="provider" xsi:type="string">checkoutProvider</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
<item name="validate-no-empty" xsi:type="boolean">true</item>
</item>
<item name="sortOrder" xsi:type="number">0</item>
</item>
</item>
</item>
</item>
</item>
</item>
How can I get values from a class into the dropdown? Right now, I only can access values from the quote class. I need to access my own (just fyi: to show different availabilities for the different stores)
If more infos needed, feel free to ask for them. Thank you in advance.
Ok, i figured it out.
I added an index-controller <Your_Vendor>/<YourModule>/Controller/Options/index.php, and declared it in <Your_Vendor>/<YourModule>/etc/frontent/routes.xml and can get the values with ajax:
updateDropdownValues: function(method) {
var valuesCollection = [];
if(method['carrier_code'] == 'customshipping'){
$.ajax({
url:"/<your_declared_route>/Optionen/index",
contentType: "application/json",
async:false,
success:function (data) {
valuesCollection = [];
var wert=[];
$.each(data, function (index, thevalue) {
wert=[];
wert["label"]=index;
wert["value"]=thevalue;
valuesCollection.push(wert);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.log("There has been an error retrieving the values from the database.");
}
});
}
else {
valuesCollection = [];
}
self.updateDropdown(valuesCollection);
},
My routes.xml:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="yourid" frontName="<your_declared_route>">
<module name="<your_Vendor/Your_Modulname>" />
</route>
</router>
</config>
I will extend this answer with custom collection( Custom Table ) for any type of dropdown generation. Ex - Show Stores Drop Down.
let customurl = urlBuilder.build('pickupstores/storeoptions/index');
// urlBuilder.build('frontname/storeoptions/index');
updateDropdownValues: function(method) {
var valuesCollection = [];
if(method['carrier_code'] === 'storepickup'){ //You can add your own logic here,
//I added this to show stores dropdown only customer choose custom shipping method **storepickup**
$.ajax({
url:customurl,
type: 'POST',
contentType: "application/json",
async:false,
success:function (data) {
valuesCollection = [];
$.each(JSON.parse(data) , function(index, val) {
valuesCollection.push({
label: val,
value: val
});
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.log("There has been an error retrieving the values from the database.");
}
});
}
self.updateDropdown(valuesCollection);
},
My Controller file
<?php
namespace Ayakil\CustomShippingMethod\Controller\StoreOptions;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\Exception\NotFoundException;
use Ayakil\PickupStores\Model\PickupStores; // My custom module to get stores
use Magento\Framework\Controller\Result\JsonFactory;
class Index implements HttpPostActionInterface
{
protected $pickupStores;
protected $resultJsonFactory;
public function __construct(
PickupStores $pickupStores,
JsonFactory $resultJsonFactory,
array $data = array()
) {
$this->pickupStores = $pickupStores;
$this->resultJsonFactory = $resultJsonFactory;
}
public function execute(){
$resultJson = $this->resultJsonFactory->create();
$collection = $this->pickupStores->getCollection();
$storesCollection = $collection->getData();
$stores = [];
foreach($storesCollection as $store){
$stores[] = $store['store_name'];
}
return $resultJson->setData(json_encode($stores));
}
}
I hope this answer will save some ones time in future.

Using compiled bindings with Prism

I want to use compiled bindings in my Xamarin Forms app in combination with Prism.
I created a small xamarin forms app with a simple view, viewmodel and prism (prism:ViewModelLocator.AutowireViewModel="True"). Classic binding works as expected.
How should I implemented compiled binding without creating the binding context twice?
Classic binding with prism: HomePage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="CompiledBinding.Views.HomePage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="{Binding Name}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
HomePageViewModel.cs:
using Prism.Mvvm;
using Prism.Navigation;
using System;
using Xamarin.Forms;
namespace CompiledBinding.ViewModels
{
public class HomePageViewModel : BindableBase
{
string _name = "Compiled binding test";
public HomePageViewModel(INavigationService navigationService)
{
var nav = navigationService;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
// Do something
Name = DateTime.Now.ToString("yyyy MMMM dd hh:mm:ss");
return true; // True = Repeat again, False = Stop the timer
});
}
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
}
}
Adding the binding context to the xaml page again, is not an option:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
xmlns:viewModels="clr-namespace:CompiledBinding.ViewModels"
x:Class="CompiledBinding.Views.HomePage"
x:DataType="viewModels:HomePageViewModel">
<ContentPage.BindingContext>
<viewModels:HomePageViewModel />
</ContentPage.BindingContext>
<StackLayout>
<!-- Place new controls here -->
<Label Text="{Binding Name}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Besides of defining the binding context again, it also results in the error: no public parameterless constructor.
Do I oversee something? Does anyone know how to work with compiled bindings together with prism?

sapui5 access to controller without id

i'm new at sapui5. I have a List where each element contains a Button and an Image. I want to change the image src by pressing button (only imagewhich is part of list element same as button). Is it possible to get access to image withou id? (How to do it?)
Xml code:
<List items="{data>/Stages}">
<CustomListItem>
<Panel>
<headerToolbar>
<Toolbar class="topDetailToolbar" style="Clear">
<Title class="sapUiSmallMarginBegin fieldWorkTitle" text="{data>Name}" titleStyle="H2" />
<ToolbarSpacer />
<Button text="{i18n>TECH_CARD_ROLL}" class="addButton sapUiSmallMarginBottom" press="onVisibleFilters" />
<core:Icon src="sap-icon://navigation-up-arrow" size="1rem" color="#00c0db" visible="{confFilter>/filterUp}" />
</Toolbar>
</headerToolbar>
</Panel>
</CustomListItem>
</List>
You can achieve it by adding the style class to icon and get the instance of the icon using jQuery and reset using setSrc()
Event handler - onVisibleFilters to change the icon src
onVisibleFilters: function(oEvent) {
var oToolbarId = oEvent.getSource().getParent().sId;//get Parent toolbar of button
var sIconId = jQuery("#" + oToolbarId).find(".hdrIcon").attr("id");//get Icon id using jQuery and hdrIcon class
if(sIconId) {
var oIcon = sap.ui.getCore().byId(sIconId);
if(oIcon) oIcon.setSrc("sap-icon://lab");//update the icon src
}
}
Here's what you should do:
var oButton = oEvent.getSource(); //this returns the button which triggers the press event
var oListItem = oButton.getParent(); //returns the listItem in which the button was pressed
var aCells = oListItem.getAggregation("cells");
you should be able to find the image in one of the indexes in the cells array.