Xamarin Android - 当我第一次添加视图时,FrameLayout 只显示它的背景,但当我再次添加它时显示它
Xamarin Android - FrameLayout display only it's background when i add view first time, but displayed when i add it again
我有一个很奇怪的问题。我有一个自定义的 FrameLayout(它只有一个字符串 FileName 与 mvvmcross 和一些方法绑定)。
我用它在项目点击时显示媒体(Pdf、视频、声音和图片)。
我的项目是代表我的媒体文件并绑定到 mediaItems 的小图标。
当我点击这些图标之一时,当我到达断点时一切正常,framelyout 出现,但它只显示它的背景而不是它的子视图。
如果我缩小它并再次单击同一个项目,框架布局将再次出现并正确显示我的内容,我不知道为什么。
要了解其背后的逻辑,请查看其工作原理:
我点击了我的一项
在我的视图模型中,它引发了 onclick 命令,并设置了我的 属性 SelectedMedia
包含我的自定义 frameLayout 的视图,将其可见性从 gone 变为可见,因为它的可见性已绑定到 SelectedMedia(如果为 null=>gone if not => visible)
同时我的自定义 FrameLayout 设置了 属性 文件名(绑定在 属性 SelectedMedia.FileName)。
FileName setter(你可以在代码saple中看到)调用我的Init方法,谁的工作就是select将哪种视图添加到我的自定义然后添加FrameLayout
我的容器终于出现了,里面有我自定义的FrameLayout,但我只能看到它的背景,而不是它的子视图,我不知道为什么。
这是我的自定义框架布局 C# 代码:
public class MediaController : FrameLayout
{
#region [ Fields ]
private Context _context;
private ImageController _imageController;
private SoundAndVideoController _soundAndVideoController;
private PdfController _pdfController;
private LayoutInflater _layoutInflater;
private readonly string[] supportedVideoFormat = { "mp4", "3gp", "mkv", "mpg" };
private readonly string[] supportedPictureFormat = { "png", "bmp", "gif", "jpg" };
private readonly string[] supportedAudioFormat = { "flac", "mp3", "wav" };
private readonly string[] supportedPdfFormat = { "pdf" };
#endregion
#region [ Properties ]
private string _fileName;
public string FileName
{
get
{
return _fileName;
}
set
{
if (value != null)
{
_fileName = value;
Init();
}
}
}
#endregion
#region [ Constructors ]
public MediaController(Activity activity) : base(activity)
{
_context = activity.BaseContext;
Init();
}
public MediaController(Context context) : base(context)
{
_context = context;
Init();
}
public MediaController(Context context, IAttributeSet attrs) : base(context, attrs)
{
_context = context;
Init();
}
public MediaController(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
_context = context;
Init();
}
public MediaController(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
{
_context = context;
Init();
}
#endregion
#region [ Methods ]
public void InitViews()
{
}
private void Init()
{
if (!string.IsNullOrEmpty(FileName) &&_context != null)
{
this.RemoveAllViews();
string extension = FileName.Split('.').Last();
_layoutInflater = (LayoutInflater)_context.GetSystemService(Context.LayoutInflaterService);
if (supportedAudioFormat.Any(extension.ToLower().Contains) || supportedVideoFormat.Any(extension.ToLower().Contains))
{
InitMusicOrVideoPlayer(extension);
}
else if (supportedPictureFormat.Any(extension.ToLower().Contains))
{
InitImageViewer();
}
else if (supportedPdfFormat.Any(extension.ToLower().Contains))
{
InitPdfViewer();
}
else
{
//manage error;
}
}
}
private void InitMusicOrVideoPlayer(string fileExtension)
{
SurfaceView musicView = (SurfaceView)layoutInflater.Inflate(Resource.Layout.MusicVideoTemplate, null);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(this.Width, this.Height);
this.AddView(musicView, layoutParams);
if (supportedAudioFormat.Any(fileExtension.ToLower().Contains))
{
ImageView imageView = new ImageView(_context);
imageView.Background = _context.GetDrawable(Resource.Drawable.speaker);
imageView.SetScaleType(ImageView.ScaleType.FitCenter);
layoutParams = new FrameLayout.LayoutParams(this.Width / 4, this.Height / 4);
layoutParams.SetMargins((int)(this.Width * 0.375f), (int)(this.Height * 0.375f), 0, 0);
this.AddView(imageView, layoutParams);
soundAndVideoController = new SoundAndVideoController(musicView, FileName, _context, true);
}
else
{
soundAndVideoController = new SoundAndVideoController(musicView, FileName, _context, false);
}
}
private void InitPdfViewer()
{
FrameLayout pdfContainer = (FrameLayout)_layoutInflater.Inflate(Resource.Layout.PdfTemplate, null);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(this.Width, this.Height);
this.AddView(pdfContainer, layoutParams);
_pdfController = new PdfController(FileName, pdfContainer, _context);
}
private void InitImageViewer()
{
FrameLayout mediaImageContainer = (FrameLayout)_layoutInflater.Inflate(Resource.Layout.MediaImageTemplate, null);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(this.Width, this.Height);
this.AddView(mediaImageContainer, layoutParams);
_imageController = new ImageController(FileName, mediaImageContainer);
}
#endregion
}
这是我的 xml,其中包含我的自定义框架布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_gravity="center"
android:background="@color/Black"
local:MvxBind="Visibility MustShowMedias, Converter=Visibility ">
<LinearLayout
android:orientation="horizontal"
android:weightSum="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/MediaLeftLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.05">
<Button
android:id="@+id/MediaPreviousButton"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_gravity="center"
android:text="Previous" />
</LinearLayout>
<LinearLayout
android:id="@+id/MediaCenterLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.9"
android:orientation="vertical"
android:weightSum="1">
<space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.05" />
<MyProject.Droid.Views.MediaControllers.MediaController
android:id="@+id/MediaContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.9"
android:background="#FFFFFF"
local:MvxBind="FileName SelectedMedia.Source">
</MyProject.Droid.Views.MediaControllers.MediaController>
</LinearLayout>
<LinearLayout
android:id="@+id/MediaRightLayout"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.05">
<Button
android:id="@+id/MediaCloseButton"
android:layout_width="match_parent"
android:layout_height="35dp"
android:textColor="#FF0000"
android:text="X"
local:MvxBind="Click CloseMediaWindowCommand" />
<Button
android:id="@+id/MediaNextButton"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_gravity="center"
android:text="Next" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
我在 Android 开发方面还很陌生,我完全不知道为什么这不起作用。也许我的框架布局没有完全加载(这很奇怪,因为它包含在我的视图中)。我非常愿意接受任何关于这个问题的帮助!
谢谢
编辑:
好的,这里有一些更新:
- 我尝试使用 BringChildToFront、setFocus 将包含我的框架布局的视图设置为可点击(因为我注意到我的点击正在经历)。
编辑 2:
我更新了我的代码(仍然没有按预期工作)
我试图在构造函数调用时设置我的布局,这打破了我第二次尝试加载它时视图 dsiplay 的事实,让我有一个空白的框架布局,所以我回到老办法
PS:抱歉我的英语很糟糕
好的,我终于解决了这个问题!
出于某些原因和一些我还不了解的 android 行为,我的视图在加载此视图之前已添加到我的自定义框架布局中。
所以我找到的解决方案是将 ViewTreeObserver 添加到我的自定义布局,然后将我的子视图加载到那里:
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
ViewTreeObserver vto = this.ViewTreeObserver;
vto.AddOnGlobalLayoutListener(this);
vto.GlobalLayout += (sender, args) =>
{
if (!_hasLoaded)
{
Init();
_hasLoaded =true;
}
};
}
我有一个很奇怪的问题。我有一个自定义的 FrameLayout(它只有一个字符串 FileName 与 mvvmcross 和一些方法绑定)。 我用它在项目点击时显示媒体(Pdf、视频、声音和图片)。 我的项目是代表我的媒体文件并绑定到 mediaItems 的小图标。
当我点击这些图标之一时,当我到达断点时一切正常,framelyout 出现,但它只显示它的背景而不是它的子视图。
如果我缩小它并再次单击同一个项目,框架布局将再次出现并正确显示我的内容,我不知道为什么。
要了解其背后的逻辑,请查看其工作原理:
我点击了我的一项
在我的视图模型中,它引发了 onclick 命令,并设置了我的 属性 SelectedMedia
包含我的自定义 frameLayout 的视图,将其可见性从 gone 变为可见,因为它的可见性已绑定到 SelectedMedia(如果为 null=>gone if not => visible)
同时我的自定义 FrameLayout 设置了 属性 文件名(绑定在 属性 SelectedMedia.FileName)。
FileName setter(你可以在代码saple中看到)调用我的Init方法,谁的工作就是select将哪种视图添加到我的自定义然后添加FrameLayout
我的容器终于出现了,里面有我自定义的FrameLayout,但我只能看到它的背景,而不是它的子视图,我不知道为什么。
这是我的自定义框架布局 C# 代码:
public class MediaController : FrameLayout
{
#region [ Fields ]
private Context _context;
private ImageController _imageController;
private SoundAndVideoController _soundAndVideoController;
private PdfController _pdfController;
private LayoutInflater _layoutInflater;
private readonly string[] supportedVideoFormat = { "mp4", "3gp", "mkv", "mpg" };
private readonly string[] supportedPictureFormat = { "png", "bmp", "gif", "jpg" };
private readonly string[] supportedAudioFormat = { "flac", "mp3", "wav" };
private readonly string[] supportedPdfFormat = { "pdf" };
#endregion
#region [ Properties ]
private string _fileName;
public string FileName
{
get
{
return _fileName;
}
set
{
if (value != null)
{
_fileName = value;
Init();
}
}
}
#endregion
#region [ Constructors ]
public MediaController(Activity activity) : base(activity)
{
_context = activity.BaseContext;
Init();
}
public MediaController(Context context) : base(context)
{
_context = context;
Init();
}
public MediaController(Context context, IAttributeSet attrs) : base(context, attrs)
{
_context = context;
Init();
}
public MediaController(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
_context = context;
Init();
}
public MediaController(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
{
_context = context;
Init();
}
#endregion
#region [ Methods ]
public void InitViews()
{
}
private void Init()
{
if (!string.IsNullOrEmpty(FileName) &&_context != null)
{
this.RemoveAllViews();
string extension = FileName.Split('.').Last();
_layoutInflater = (LayoutInflater)_context.GetSystemService(Context.LayoutInflaterService);
if (supportedAudioFormat.Any(extension.ToLower().Contains) || supportedVideoFormat.Any(extension.ToLower().Contains))
{
InitMusicOrVideoPlayer(extension);
}
else if (supportedPictureFormat.Any(extension.ToLower().Contains))
{
InitImageViewer();
}
else if (supportedPdfFormat.Any(extension.ToLower().Contains))
{
InitPdfViewer();
}
else
{
//manage error;
}
}
}
private void InitMusicOrVideoPlayer(string fileExtension)
{
SurfaceView musicView = (SurfaceView)layoutInflater.Inflate(Resource.Layout.MusicVideoTemplate, null);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(this.Width, this.Height);
this.AddView(musicView, layoutParams);
if (supportedAudioFormat.Any(fileExtension.ToLower().Contains))
{
ImageView imageView = new ImageView(_context);
imageView.Background = _context.GetDrawable(Resource.Drawable.speaker);
imageView.SetScaleType(ImageView.ScaleType.FitCenter);
layoutParams = new FrameLayout.LayoutParams(this.Width / 4, this.Height / 4);
layoutParams.SetMargins((int)(this.Width * 0.375f), (int)(this.Height * 0.375f), 0, 0);
this.AddView(imageView, layoutParams);
soundAndVideoController = new SoundAndVideoController(musicView, FileName, _context, true);
}
else
{
soundAndVideoController = new SoundAndVideoController(musicView, FileName, _context, false);
}
}
private void InitPdfViewer()
{
FrameLayout pdfContainer = (FrameLayout)_layoutInflater.Inflate(Resource.Layout.PdfTemplate, null);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(this.Width, this.Height);
this.AddView(pdfContainer, layoutParams);
_pdfController = new PdfController(FileName, pdfContainer, _context);
}
private void InitImageViewer()
{
FrameLayout mediaImageContainer = (FrameLayout)_layoutInflater.Inflate(Resource.Layout.MediaImageTemplate, null);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(this.Width, this.Height);
this.AddView(mediaImageContainer, layoutParams);
_imageController = new ImageController(FileName, mediaImageContainer);
}
#endregion
}
这是我的 xml,其中包含我的自定义框架布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_gravity="center"
android:background="@color/Black"
local:MvxBind="Visibility MustShowMedias, Converter=Visibility ">
<LinearLayout
android:orientation="horizontal"
android:weightSum="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/MediaLeftLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.05">
<Button
android:id="@+id/MediaPreviousButton"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_gravity="center"
android:text="Previous" />
</LinearLayout>
<LinearLayout
android:id="@+id/MediaCenterLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.9"
android:orientation="vertical"
android:weightSum="1">
<space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.05" />
<MyProject.Droid.Views.MediaControllers.MediaController
android:id="@+id/MediaContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.9"
android:background="#FFFFFF"
local:MvxBind="FileName SelectedMedia.Source">
</MyProject.Droid.Views.MediaControllers.MediaController>
</LinearLayout>
<LinearLayout
android:id="@+id/MediaRightLayout"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.05">
<Button
android:id="@+id/MediaCloseButton"
android:layout_width="match_parent"
android:layout_height="35dp"
android:textColor="#FF0000"
android:text="X"
local:MvxBind="Click CloseMediaWindowCommand" />
<Button
android:id="@+id/MediaNextButton"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_gravity="center"
android:text="Next" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
我在 Android 开发方面还很陌生,我完全不知道为什么这不起作用。也许我的框架布局没有完全加载(这很奇怪,因为它包含在我的视图中)。我非常愿意接受任何关于这个问题的帮助!
谢谢
编辑: 好的,这里有一些更新:
- 我尝试使用 BringChildToFront、setFocus 将包含我的框架布局的视图设置为可点击(因为我注意到我的点击正在经历)。
编辑 2:
我更新了我的代码(仍然没有按预期工作)
我试图在构造函数调用时设置我的布局,这打破了我第二次尝试加载它时视图 dsiplay 的事实,让我有一个空白的框架布局,所以我回到老办法
PS:抱歉我的英语很糟糕
好的,我终于解决了这个问题!
出于某些原因和一些我还不了解的 android 行为,我的视图在加载此视图之前已添加到我的自定义框架布局中。
所以我找到的解决方案是将 ViewTreeObserver 添加到我的自定义布局,然后将我的子视图加载到那里:
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
ViewTreeObserver vto = this.ViewTreeObserver;
vto.AddOnGlobalLayoutListener(this);
vto.GlobalLayout += (sender, args) =>
{
if (!_hasLoaded)
{
Init();
_hasLoaded =true;
}
};
}