I have a problem with the images inside recyclerview
They shown like this
My code to load the image is :
#BindingAdapter("imageUrl")
fun ImageView.bindImage(imgUrl: String?) {
imgUrl?.let {
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build().toString()
val uiHandler = Handler(Looper.getMainLooper())
thread(start = true) {
val bitmap = downloadBitmap(imgUri)
uiHandler.post {
this.setImageBitmap(bitmap)
}
}
}
}
fun downloadBitmap(imageUrl: String): Bitmap? {
return try {
val conn = URL(imageUrl).openConnection()
conn.connect()
val inputStream = conn.getInputStream()
val bitmap = BitmapFactory.decodeStream(inputStream)
inputStream.close()
bitmap
} catch (e: Exception) {
Log.e(ContentValues.TAG, "Exception $e")
null
}
}
XML for item:
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_song_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
app:imageUrl="#{songObject.songImage}"
android:src="#drawable/img_song_cover" />
And XML For Recycler:
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_home_albums_list"
android:layout_width="match_parent"
android:layout_height="#dimen/dp200w"
android:layout_marginStart="#dimen/dp16w"
android:layout_marginLeft="#dimen/dp16w"
android:layout_marginTop="#dimen/dp8w"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_home_albums_title"
tools:listitem="#layout/item_album" />
My task is to do all the work without using any third-party,
So any help ?
I have solved the problem just add a statement to check if the image loaded before to not render it more than once when I scroll with recycler view, and remove the place holder.
if(this.drawable == null) {
imgUrl?.let {
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build().toString()
val uiHandler = Handler(Looper.getMainLooper())
thread(start = true) {
val bitmap = downloadBitmap(imgUri)
uiHandler.post {
this.setImageBitmap(bitmap)
}
}
}
}
Related
My observable collection is not getting updated. Once user views post and goes back to his home page he needs to go to another page to refresh his home page to reflect his last seen article.
So far example user sees article Coffee, goes back to his HP and there is no article Coffee in the collection. Then he goes to his profile(or any other page) and then goes back to HP and there is updated collection with article coffee. I have I notifyproperty
HomePage
public ArticleBrowser()
{
InitializeComponent();
Load();
}
private async void Load()
{
BindingContext = new MyArticlesBrowserViewModel();
if (BindingContext is MyArticlesBrowserViewModel)
{
var context = new MyArticlesBrowserViewModel();
await context.LoadDataForBestSellers();
lastThreeArticlesCarouselView.ItemsSource = null;
lastThreeArticlesCarouselView.ItemsSource = context.LastThreeArticles;
bestSellersCarouselView.ItemsSource = context.ListOfBestSellers;
}
}
<local:ExtendedCarouselViewControl x:Name="lastThreeArticlesCarouselView"
Grid.Row ="1"
HeightRequest="250"
ShowIndicators="True"
Margin="0"
VerticalOptions="Start"
IndicatorsTintColor="{ DynamicResource TranslucidBlack }"
CurrentPageIndicatorTintColor="{ DynamicResource BaseTextColor }"
ItemsSource="{ Binding LastThreeArticles, Mode=TwoWay }">
<cv:CarouselViewControl.ItemTemplate>
<DataTemplate>
<local:AvatArticlesBrowserHeaderItemTemplate />
</DataTemplate>
</cv:CarouselViewControl.ItemTemplate>
</local:ExtendedCarouselViewControl>
ViewModel
private static List<Article> _lastOpenedArticles;
private static List<DownloadedArticle> _allDownloadedArticles;
private static List<Article> _lastSeenArticles;
public ObservableCollection<ArticleDetailData> LastThreeArticles { get; } = new ObservableCollection<ArticleDetailData>();
void ShowLastListened()
{
var downloadedArticles = LangUpDataSaverLoader.DeserializeAllOptimizationData();
if (_lastOpenedArticles != null && _lastOpenedArticles.Count > 0)
{
foreach (var article in _lastOpenedArticles.Take(3))
{
var filename = string.Format(SharedConstants.ArticleImageUrl, SharedConstants.ApiBaseUri, article.Id);
var newCell = new ArticleDetailData()
{
Author = article.Author,
Description = article.Description,
Body = article.Description,
Section = article.Category,
Id = article.Id,
Subtitle = article.Description,
Title = article.NameCz,
WhenDay = article.DateCreate.Day.ToString() + " / ",
WhenMonth = article.DateCreate.Month.ToString() + " / ",
WhenYear = article.DateCreate.Year.ToString(),
FullDate = article.DateCreate.ToLongDateString(),
NumberOfWords = article.NumberOfWords,
AmountOfGrammarDescription = article.AmountOfGrammarDescription,
ArticleLength = article.ArticleLength,
Price = article.Price,
IsSubmitted = article.IsSubmitted,
BestSellerRating = article.BestSellerRating,
};
if (downloadedArticles.DownloadedArticles.Any(m => m.Id == article.Id))
{
newCell.BackgroundImage = article.Id.ArticleImageFile();
}
newCell.BackgroundImage = filename;
LastThreeArticles.Add(newCell);
}
}
}
public async Task LoadDataForBestSellers()
{
var articlesApiResponse = await AVAT.App.ApiFactory.GetBestSellerArticlesAsync();
var allArticles = articlesApiResponse.Match(articles => articles.ToList(), _ => new List<Article>());
FillArticles(allArticles);
if (LangUpLoggedUser.LoggedIn || LangUpLoggedUser.LoggedOffline)
{
LastThreeArticles.Clear();
var lastOpenedArticle = LangUpDataSaverLoader.DeserializeLastLoadedArticle();
lastOpenedArticle.Reverse();
_lastOpenedArticles = lastOpenedArticle;
ShowLastListened();
}
else
{
var freeArticlesApiResponse = await AVAT.App.ApiFactory.GetAllFreeArticlesAsync();
var allUserArticles = articlesApiResponse.Match(articles => articles.ToList(), _ => new List<Article>());
FillAnonymousArticles(allUserArticles);
}
}
I have tried Refresh Command but i was not getting any data back
public ICommand RefreshCommand { get; }
public MyArticlesBrowserViewModel()
: base()
{
RefreshCommand = new Command(async () => await ExecuteRefreshCommand());
}
async Task ExecuteRefreshCommand()
{
if (IsBusy) return;
IsBusy = true;
try
{
await LoadDataForBestSellers();
}
finally
{
IsBusy = false;
}
}
Solved with
protected override void OnAppearing()
{
base.OnAppearing();
var context = new MyArticlesBrowserViewModel();
lastThreeArticlesCarouselView.ItemsSource = null;
Task.Run(async () => await context.LoadDataForBestSellers()).Wait();
bestSellersCarouselView.ItemsSource = context.ListOfBestSellers;
lastThreeArticlesCarouselView.ItemsSource = context.LastThreeArticles;
}
I am implementing a game in my xamarin forms application, a name match game. It has two lists: one for showing the images and the other one for showing the names. The player taps the image from the top list and then taps the name from the bottom list(or name first then image). If they match the player gets points and tapped image and name will be removed from lists.
I am using flowlistview for showing the image list and name list because I need to show multiple items in a row. When tapping the image and name I have done the matching and remove the image and name if they matched. But I need to highlight the selected image or selected name when tapping and disable selection for other items. I have done highlighting feature using this thread, but it is not working perfectly. Sometimes multiple images are highlighting and sometimes when selecting an image on the top name on the below list is automatically highlighting.
I have created a sample project and uploaded it here. Please help me to complete this game. We have this game on our website, https://www.catholicbrain.com/edu-namematch/39524/1/the-two-great-commandments , please have a look at it for the working of the game. I will give you login details by DM.
Edit 1
#LucasZhang-MSFT I am accepting that, but the current question is different. It has 2 different flowlistviews. On the top an image list and on the bottom a name list. This is a simple game for kids, the player taps the image from the top list and then taps the name from the bottom list(or name first then image). If they match the player gets points and tapped image and name will be removed from lists. When not match I reset the items background colors like below:
foreach (var item1 in ImageItems)
{
item.BGColor = Color.White;
}
foreach (var item2 in NameItems)
{
item.BGColor = Color.White;
}
OnPropertyChanged("NameMatchImagItems");
OnPropertyChanged("NameMatchNameItems");
After this point, multiple images are highlighting and sometimes when selecting an image on the top name on the below list is automatically highlighting.
If you have time, can you please download the sample and have a look? I tried my best, but no luck.
Cause:
You set the ItemsSource of two flowlistview with the same source _allItems !!
Solution:
in xaml
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<!--imageflowlistview-->
<flv:FlowListView
x:Name="NameMatchImageList"
FlowItemTappedCommand="{Binding ImageItemTappedCommand}"
FlowItemsSource="{Binding ImageItems}"
FlowColumnCount="2"
FlowLastTappedItem="{Binding LastImageTappedItem}"
HasUnevenRows="True">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<StackLayout BackgroundColor="{Binding BGColor}" Orientation="Vertical">
<Frame
Padding="5"
Margin="5"
HasShadow="False"
BorderColor="#a4e6f9"
CornerRadius="15">
<ffimageloading:CachedImage
Source="{Binding imageUrl, Converter={StaticResource urlJoinConverter}}"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
HeightRequest="100"
Aspect="AspectFill"/>
</Frame>
</StackLayout>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
<!--NamesFlowlistview-->
<flv:FlowListView
x:Name="NameMatchNameList"
FlowItemTappedCommand="{Binding NameItemTappedCommand}"
FlowItemsSource="{Binding NameItems}"
FlowColumnCount="2"
FlowLastTappedItem="{Binding LastNameTappedItem}"
HasUnevenRows="True">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<StackLayout Orientation="Vertical">
<Label
TextColor="Black"
FontSize="Large"
BackgroundColor="{Binding BGColor}"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding name}"/>
</StackLayout>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
</StackLayout>
</ContentPage.Content>
in code behind
namespace FlowListView_Tap
{
class NameMatchViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<NameMatchList> imageItems;
public ObservableCollection<NameMatchList> ImageItems { get
{
return imageItems;
}
set {
if(value!=null)
{
imageItems = value;
OnPropertyChanged("ImageItems");
}
}
}
public ObservableCollection<NameMatchList> nameItems;
public ObservableCollection<NameMatchList> NameItems
{
get
{
return nameItems;
}
set
{
if (value != null)
{
nameItems = value;
OnPropertyChanged("NameItems");
}
}
}
public bool isImageSelected = false;
public bool isNameSelected = false;
public ICommand NameItemTappedCommand { get; set; }
public ICommand ImageItemTappedCommand { get; set; }
private NameMatchList lastImageTappedItem;
public NameMatchList LastImageTappedItem
{
get
{
return lastImageTappedItem;
}
set
{
if(value!=null)
{
lastImageTappedItem = value;
OnPropertyChanged("LastImageTappedItem");
}
}
}
private NameMatchList lastNameTappedItem;
public NameMatchList LastNameTappedItem
{
get
{
return lastNameTappedItem;
}
set
{
if (value != null)
{
lastNameTappedItem = value;
OnPropertyChanged("LastNameTappedItem");
}
}
}
public NameMatchViewModel()
{
ImageItemTappedCommand = new Command((obj) => {
try
{
//reset the bg color
foreach (var item in ImageItems)
{
item.BGColor = Color.White;
}
NameMatchList imageList = obj as NameMatchList;
int index = ImageItems.IndexOf(imageList);
imageList.BGColor = Color.Red;
///ImageItems.RemoveAt(index);
//ImageItems.Insert(index, imageList);
//Storing name and imageurl to local db
Application.Current.Properties["NameMatchImageList_Image"] = imageList.imageUrl;
Application.Current.Properties["NameMatchImageList_Name"] = imageList.name;
Application.Current.Properties["ImageItem"] = imageList;
isImageSelected = true;
if (isImageSelected && isNameSelected)
{
//If both image and name selected by player startes checking the matching
StartNameMatchCheck(imageList);
}
}
catch (Exception imagetapEx)
{
Debug.WriteLine("imagetapEx:>>" + imagetapEx);
}
});
NameItemTappedCommand = new Command((obj) => {
try
{
//reset the bg color
foreach (var item in NameItems)
{
item.BGColor = Color.White;
}
NameMatchList nameList = obj as NameMatchList;
int index = NameItems.IndexOf(nameList);
nameList.BGColor = Color.Red;
//NameItems.RemoveAt(index);
//NameItems.Insert(index, nameList);
//Storing name and imageurl to local db
Application.Current.Properties["NameMatchNameList_Image"] = nameList.imageUrl;
Application.Current.Properties["NameMatchNameList_Name"] = nameList.name;
Application.Current.Properties["NameItem"] = nameList;
isNameSelected = true;
if (isImageSelected && isNameSelected)
{
//If both image and name selected by player startes checking the matching
StartNameMatchCheck(nameList);
}
}
catch (Exception nametapEx)
{
Debug.WriteLine("nametapEx:>>" + nametapEx);
}
});
}
public async void StartNameMatchCheck(NameMatchList item)
{
isImageSelected = false;
isNameSelected = false;
//Fetching data from local db
string NameMatchImageListImage = Application.Current.Properties["NameMatchImageList_Image"].ToString();
string NameMatchImageListName = Application.Current.Properties["NameMatchImageList_Name"].ToString();
string NameMatchNameListImage = Application.Current.Properties["NameMatchNameList_Image"].ToString();
string NameMatchNameListName = Application.Current.Properties["NameMatchNameList_Name"].ToString();
//Match check
if ((NameMatchImageListImage == NameMatchNameListImage) && (NameMatchImageListName == NameMatchNameListName))
{
await Application.Current.MainPage.DisplayAlert("Alert", "Success", "Ok");
//Removing the items from list if they match
ImageItems.Remove(LastImageTappedItem);
NameItems.Remove(LastNameTappedItem);
LastImageTappedItem = null;
LastNameTappedItem = null;
}
else
{
await Application.Current.MainPage.DisplayAlert("Alert", "Failed", "Ok");
//resetting the colors
LastImageTappedItem.BGColor = Color.White;
LastNameTappedItem.BGColor = Color.White;
}
}
public async void CallNameMatch()
{
try
{
//HttpClient client = new HttpClient();
//var nameMatchResponse = await client.GetAsync("");
//if (nameMatchResponse.IsSuccessStatusCode)
//{
// var Response = await nameMatchResponse.Content.ReadAsStringAsync();
// var imageResponse = JsonConvert.DeserializeObject<Games>(Response.ToString());
// var namematch = JsonConvert.DeserializeObject<Games>(Response.ToString());
ImageItems = new ObservableCollection<NameMatchList>();
ImageItems.Add(new NameMatchList() { name = "Comfort the Sorrowing", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/06/971/head/Comfort the Sorrowing.png" });
ImageItems.Add(new NameMatchList() { name = "Giving Food To The Hungry", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/23/784/head/Giving Food To The Hungry.png" });
ImageItems.Add(new NameMatchList() { name = "Pray for the Living and The Dead", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/39/707/head/Pray for the Living and The Dead.png" });
ImageItems.Add(new NameMatchList() { name = "To bury the Dead", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/54/828/head/To bury the Dead.png" });
//shuffling image list
//Random r1 = new Random();
//int randomIndex1 = 0;
//while (ImageItems.Count > 0)
//{
// randomIndex1 = r1.Next(0, ImageItems.Count);
// ImageItems[randomIndex1].BGColor = Color.White;
// ImageItems.Add(ImageItems[randomIndex1]);
// ImageItems.RemoveAt(randomIndex1);
//}
//NameMatchImagItems = new ObservableCollection<NameMatchList>(ImageItems);
NameItems = new ObservableCollection<NameMatchList>();
NameItems.Add(new NameMatchList() { name = "To bury the Dead", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/54/828/head/To bury the Dead.png" });
NameItems.Add(new NameMatchList() { name = "Pray for the Living and The Dead", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/39/707/head/Pray for the Living and The Dead.png" });
NameItems.Add(new NameMatchList() { name = "Comfort the Sorrowing", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/06/971/head/Comfort the Sorrowing.png" });
NameItems.Add(new NameMatchList() { name = "Giving Food To The Hungry", imageUrl = "/cbrain-app/files/doc-lib/2018/02/22/11/46/23/784/head/Giving Food To The Hungry.png" });
//shuffling name list
//Random r2 = new Random();
//int randomIndex2 = 0;
//while (NameItems.Count > 0)
//{
// randomIndex2 = r2.Next(0, NameItems.Count);
// NameItems[randomIndex2].BGColor = Color.White;
// NameItems.Add(NameItems[randomIndex2]);
// NameItems.RemoveAt(randomIndex2);
//}
// NameMatchNameItems = new ObservableCollection<NameMatchList>(NameItems);
//}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("NMException:>" + ex);
}
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void ShowAlert(string message)
{
Device.BeginInvokeOnMainThread(async () => {
await Application.Current.MainPage.DisplayAlert("Alert", message, "Ok");
});
}
}
}
I want to implement an feature like that, an image control in xamarin.uwp, a user will select the image by file picker, and set the the image to the image control.
As far as I know, I could not set the local path directly to the file path.
How can I use with the file stream?
Update1:
xaml
<Image Grid.Row="3" Source="{Binding Image}"></Image>
ImagePageViewModel
public class ImagePageViewModel : BindableBase
{
public ImagePageViewModel()
{
}
private ImageSource _image;
public ImageSource Image
{
get { return _image; }
set { SetProperty(ref _image, value); }
}
private DelegateCommand _imageSelect;
public DelegateCommand ImageSelect =>
_imageSelect ?? (_imageSelect = new DelegateCommand(ExecuteImageSelect));
async void ExecuteImageSelect()
{
try
{
var picker = new Windows.Storage.Pickers.FileOpenPicker
{
ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail,
SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary
};
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
Image = ImageSource.FromStream(() => fileStream.AsStream());
}
}
else
{
ImageUri = "";
}
}
catch (Exception ex)
{
throw ex;
}
}
}
A collection of images are showing in GridView using Xamarin Android with Mvvm Cross, but the problem is there are two button which rotates clock and anti clock direction with 90 degrees for each click all cells(or images) should be rotate within the GridView.
How can I achieve it?
Here is my viewModel collection which will be bind to GridView,
private ObservableCollection<Snapshot> _snapshotsItemSource;
public ObservableCollection<Snapshot> SnapshotsItemSource
{
get { return _snapshotsItemSource; }
set
{
_snapshotsItemSource = value;
RaisePropertyChanged(() => SnapshotsItemSource);
}
}
And my Model object is,
public class Snapshot : MvxViewModel
{
string _ID;
public string ID
{
get
{
return _ID;
}
set
{
_ID = value;
ImageUrl = string.Format("http://{0}:{1}/GetSnapshot?ID={2}", TIConstants.Device.IpAdd, TIConstants.PortNo, value);
}
}
string _ImageUrl;
public string ImageUrl
{
get
{
return _ImageUrl;
}
set
{
_ImageUrl = value;
RaisePropertyChanged("ImageUrl");
}
}
}
And My view is,
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mvvm="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<MvvmCross.Binding.Droid.Views.MvxGridView
android:id="#+id/gvSnapshots"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:numColumns="3"
android:layout_alignParentTop="true"
mvvm:MvxItemTemplate="#layout/snapshotcellview"
mvvm:MvxBind="ItemsSource SnapshotsItemSource" />
<RelativeLayout
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="#dimen/section_height"
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<ImageButton
android:id="#+id/btnRotateLeft"
android:layout_alignParentLeft="true"
android:src="#drawable/abc_text_select_handle_left_mtrl_dark"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageButton
android:id="#+id/btnRotateRight"
android:layout_alignParentRight="true"
android:src="#drawable/abc_text_select_handle_left_mtrl_dark"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
Try With Glide, is This helpful for you
Glide
.with( context )
.load( "image Url" )
.transform( new RotateTransformation( context, 90f ))
.into( imageView );
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.SnapshotsView, null);
var toolbar = ((MainActivity)this.Activity).FindViewById(Resource.Id.toolbar);
var txtTitle = ((MainActivity)this.Activity).FindViewById<TextView>(Resource.Id.TitleText);
txtTitle.Text = ViewModel.ViewTitle;
RegisterEvents();
ViewModel.SetItemSource();
var btnLeft = view.FindViewById<ImageButton>(Resource.Id.btnRotateLeft);
btnLeft.Click += BtnLeft_Click;
var btnRight = view.FindViewById<ImageButton>(Resource.Id.btnRotateRight);
btnRight.Click += BtnRight_Click;
grid = view.FindViewById<MvxGridView>(Resource.Id.gvSnapshots);
mAdapter = new SnapshotsDataViewAdapter(this.Activity, (IMvxAndroidBindingContext)BindingContext);
grid.Adapter = mAdapter;
grid.OnItemClickListener = this;
return view;
}
void BtnLeft_Click(object sender, EventArgs e)
{
currentRotation = currentRotation + 1;
mAdapter.NotifyDataSetChanged();
}
void BtnRight_Click(object sender, EventArgs e)
{
currentRotation = currentRotation - 1;
mAdapter.NotifyDataSetChanged();
}
static int currentRotation = 0;
static float RotationTranslation = 0;
private class SnapshotsDataViewAdapter : MvxAdapter
{
SnapshotsViewModel mViewModel;
public SnapshotsDataViewAdapter(FragmentActivity context, IMvxAndroidBindingContext bindingContext) : base(context, bindingContext)
{
mViewModel = bindingContext.DataContext as SnapshotsViewModel;
}
protected override View GetBindableView(View convertView, object dataContext, ViewGroup parent, int templateId)
{
View row = convertView;
try
{
var item = (BSSnapshot)dataContext;
if (row == null)
{
row = BindingContext.BindingInflate(templateId, parent, false);
}
var imgView = row.FindViewById<ImageView>(Resource.Id.imgRotate1);
Picasso.With(Android.App.Application.Context).Load(item.ImageUrl).Into(imgView);
imgView.Rotation = currentRotation*90;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{}
return row;
}
}
Here I used Picasso as Glide was not able to getting add to the project and it is working fine.
developed a webview app, I have an option to upload image (input type = "file"). In the browser functions normally, but within the webview, it does not. I would like some help to resolve this problem.
because you not post any code, take a look of my code.
It allow webview to upload image from camera or galery
class HandlingWebview(){
private var mFilePathCallback: ValueCallback<Array<Uri>>? = null
private var mCameraPhotoPath: String? = null
companion object {
const val CHOOSE_FILE_REQUEST_CODE = 9685
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
initObserver()
initView()
}
private val permissionUtils: PermissionUtils by lazy {
PermissionUtils(
this,
trackingService,
getString(R.string.rationale_storage),
Constant.RC_PERMISSIONS_DOWNLOAD_DOCS,
Constant.PERMISSIONS_DOWNLOAD_DOCS
)
}
private fun initView() {
binding.webView.settings.apply {
javaScriptEnabled = true
loadWithOverviewMode = true
useWideViewPort = true
domStorageEnabled = true
}
binding.webView.setOnKeyListener(object : View.OnKeyListener {
override fun onKey(v: View?, keyCode: Int, event: KeyEvent?): Boolean {
if (event?.action == KeyEvent.ACTION_DOWN) {
val webView = v as WebView
when (keyCode) {
KeyEvent.KEYCODE_BACK -> if (webView.canGoBack()) {
webView.goBack()
return true
}
}
}
return false
}
})
binding.webView.apply {
loadUrl(url)
}
binding.webView.webViewClient = object : WebViewClient() {
override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
super.doUpdateVisitedHistory(view, url, isReload)
}
}
binding.webView.webChromeClient = object : WebChromeClient() {
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
if (permissionUtils.isAllPermissionAllowed()) {
// Double check that we don't have any existing callbacks
startActivityChooser(fileChooserParams, filePathCallback)
} else observePermissionResult(permissionUtils.build().asLiveData(), fileChooserParams, filePathCallback)
return true
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) = permissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults)
private fun startActivityChooser(
fileChooserParams: WebChromeClient.FileChooserParams?,
filePathCallback: ValueCallback<Array<Uri>>?
) {
mFilePathCallback?.onReceiveValue(null)
mFilePathCallback = filePathCallback
activity?.packageManager?.let {
var takePictureIntent: Intent? = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent?.resolveActivity(it) != null){
var photoFile: File? = null
try {
photoFile = createImageFile()
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath)
} catch (ex: IOException) {
// Error occurred while creating the File
Timber.i("Unable to create Image File $ex")
}
// Continue only if the File was successfully created
if (photoFile != null) {
mCameraPhotoPath = "file:" + photoFile.absolutePath
takePictureIntent.putExtra(
MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile)
)
} else {
takePictureIntent = null
}
}
val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
contentSelectionIntent.type = "image/*"
val intentArray: Array<Intent?> = takePictureIntent?.let { arrayOf(it) } ?: arrayOfNulls(0)
val chooserIntent = Intent(Intent.ACTION_CHOOSER)
chooserIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser")
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
startActivityForResult(chooserIntent, CHOOSE_FILE_REQUEST_CODE)
}
}
private fun initObserver() {}
private fun observePermissionResult(
permissionResult: LiveData<Event<PermissionUtils.Companion.PermissionResult>>,
fileChooserParams: WebChromeClient.FileChooserParams?,
filePathCallback: ValueCallback<Array<Uri>>?
) {
permissionResult.observe(viewLifecycleOwner) { event ->
event?.getContentIfNotHandled()?.let {
when (it) {
is PermissionUtils.Companion.PermissionResult.Denied -> {
// pass
}
is PermissionUtils.Companion.PermissionResult.Granted -> {
// pass
}
is PermissionUtils.Companion.PermissionResult.AllGranted -> {
startActivityChooser(fileChooserParams, filePathCallback)
}
}
}
}
}
override fun useCustomBackEvent(): Boolean = true
override fun onBackEvent() {
destroyWebView()
super.onBackEvent()
}
private fun destroyWebView() {
binding.llParent.removeAllViews()
binding.webView.apply {
clearHistory()
clearCache(true)
onPause()
removeAllViews()
destroyDrawingCache()
destroy()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
CHOOSE_FILE_REQUEST_CODE -> {
var results: Array<Uri>? = null
if (resultCode == Activity.RESULT_OK && mFilePathCallback!= null) {
if (data == null) { // take photo from camera
if (mCameraPhotoPath != null) results = arrayOf(Uri.parse(mCameraPhotoPath))
} else { // image picker
data.dataString?.let { results = arrayOf(Uri.parse(it)) }
}
}
mFilePathCallback?.onReceiveValue(results)
mFilePathCallback = null
}
}
super.onActivityResult(requestCode, resultCode, data)
}
#Throws(IOException::class)
private fun createImageFile(): File? {
// Create an image file name
val timeStamp: String = getTodayDateString()
val imageFileName = "JPEG_" + timeStamp + "_"
val storageDir: File = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
)
return File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
)
}
}