如何使用 PreferenceFragmentCompat 添加可以在 PreferenceScreen 中编辑的图像视图?
How to add image view that can be edited inside a PreferenceScreen using PreferenceFragmentCompat?
PreferenceScreen 似乎不支持开箱即用的 ImageView,我该如何实现,所以它类似于 whatsapp 的。
好的,经过一些研究后,我相信以下是最新且稳定的解决方案,假设您使用的是 androidx.preference and not android.preference,该解决方案在 API 29.
中已弃用
求解步骤
- 创建自定义布局
- 通过扩展
Preference
class 创建新的自定义首选项 class
- 在您的
preference.xml
文件中添加这个新 class 的条目
- 在你的
SettingsFragment
中使用这个class
1 - 自定义布局
这是一个简单的自定义布局,其中包含我们的 ImageView
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="16dp">
<ImageView
android:id="@+id/image"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginEnd="16dp"
android:src="@drawable/profile" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Syed Ahmed Jamil"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
2 - 通过扩展 Preference
class
创建新的自定义首选项 class
我们正在重写 onBindViewHolder()
方法,因为这是我们从中提取 ImageView
.
自定义布局视图的引用
尽管此时您可以直接在 onBindViewHolder()
中为 ImageView
提供点击监听器,但在 SettingsFragment
中提供此点击监听器更有意义。这就是我们创建 setImageClickListener()
方法的原因。
我们将在第 4 步中使用 setImageClickListener()
。
public class ImageViewPreference extends Preference {
private ImageView imageView;
View.OnClickListener imageClickListener;
public ImageViewPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
//onBindViewHolder() will be called after we call setImageClickListener() from SettingsFragment
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
imageView = (ImageView)holder.findViewById(R.id.image);
imageView.setOnClickListener(imageClickListener);
}
public void setImageClickListener(View.OnClickListener onClickListener)
{
imageClickListener = onClickListener;
}
}
3 - 在您的 preference.xml
文件中添加这个新 class 的条目
现在将这个新 class 添加到您的 preference.xml
并使用 app:layout
属性设置其布局。
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<com.example.preferencefragmentsample.ImageViewPreference
app:key="image_preference"
app:layout="@layout/custom_layout" />
<Preference
app:key="notifications"
app:title="Notifications"
app:summary="Enable or disable notifications"
app:icon="@drawable/ic_notifications_24dp"
app:iconSpaceReserved="false"
/>
<Preference
app:key="feedback"
app:summary="Get to know the developer"
app:title="About"
app:icon="@drawable/ic_info_outline_24dp"/>
</PreferenceScreen>
4 - 在您的 SettingsFragment
中使用此 class
现在只需使用 findPreference()
获取对 ImageViewPreference
的引用,方法是将您在 preference.xml
.
中定义的键字符串值传递给它
之后只需调用 setImageClickListener()
并在点击时提供您想要的任何功能。例如,我只是祝酒显示 "Image Clicked"
的消息
public class SettingsFragment extends PreferenceFragmentCompat {
ImageViewPreference imageViewPreference;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.prefs,rootKey);
imageViewPreference = (ImageViewPreference) findPreference("image_preference");
if (imageViewPreference != null)
imageViewPreference.setImageClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do whatever you want on image click here
Toast.makeText(getContext(), "Image Clicked", Toast.LENGTH_SHORT).show();
}
});
}
}
最终输出
更新:从 Firebase 云存储加载图像
NOTE: I haven't had the time to actually test and run this. This is just to give you a flow of how to do it. But I have carefully
checked and everything seems fine and it should run as expected. I'll
leave some minor changes to you if there are some errors regarding
firebase or converting from File to Bitmap.
首先修改 ImageViewPreference
class 以便它可以接收位图并将位图应用到 ImageView
。它类似于我们收到 onClickListener
并将其应用于 ImageView
。
public class ImageViewPreference extends Preference {
private ImageView imageView;
private Bitmap imageBitmap;
View.OnClickListener imageClickListener;
public ImageViewPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
//onBindViewHolder() will be called after we call setImageClickListener() and setBitmap() from SettingsFragment
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
imageView = (ImageView)holder.findViewById(R.id.image);
imageView.setOnClickListener(imageClickListener);
imageView.setImageBitmap(imageBitmap);
}
public void setImageClickListener(View.OnClickListener onClickListener)
{
imageClickListener = onClickListener;
}
public void setBitmap(Bitmap bitmap)
{
imageBitmap = bitmap;
}
}
现在假设您已经按照文档配置了 firebase 云存储。使用 getFile()
方法从 firebase 云存储中检索本地 File
对象中的图像,并将该文件对象转换为位图。之后只需使用我们之前创建的 setBitmap()
方法将该位图发送到 ImageViewPreference
。
public class SettingsFragment extends PreferenceFragmentCompat {
private Bitmap imageBitmap;
ImageViewPreference imageViewPreference;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.prefs,rootKey);
//Get your image in a local file and convert it into bitmap
StorageReference storageRef = FirebaseStorage.getInstance().getReference().child("images/yourImage.jpg");
File localFile = File.createTempFile("myImage", "bmp");
storageRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
//Convert File to Bitmap
imageBitmap = BitmapFactory.decodeFile(localFile.getAbsolutePath());
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
// Handle any errors
}
});
imageViewPreference = (ImageViewPreference) findPreference("image_preference");
if (imageViewPreference != null)
{
imageViewPreference.setImageClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do whatever you want on image click here
Toast.makeText(getContext(), "Image Clicked", Toast.LENGTH_SHORT).show();
}
});
//Send the downloaded bitmap to ImageViewPreference
imageViewPreference.setBitmap(imageBitmap);
}
}
}
PreferenceScreen 似乎不支持开箱即用的 ImageView,我该如何实现,所以它类似于 whatsapp 的。
好的,经过一些研究后,我相信以下是最新且稳定的解决方案,假设您使用的是 androidx.preference and not android.preference,该解决方案在 API 29.
中已弃用求解步骤
- 创建自定义布局
- 通过扩展
Preference
class 创建新的自定义首选项 class
- 在您的
preference.xml
文件中添加这个新 class 的条目 - 在你的
SettingsFragment
中使用这个class
1 - 自定义布局
这是一个简单的自定义布局,其中包含我们的 ImageView
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="16dp">
<ImageView
android:id="@+id/image"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginEnd="16dp"
android:src="@drawable/profile" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Syed Ahmed Jamil"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
2 - 通过扩展 Preference
class
我们正在重写 onBindViewHolder()
方法,因为这是我们从中提取 ImageView
.
尽管此时您可以直接在 onBindViewHolder()
中为 ImageView
提供点击监听器,但在 SettingsFragment
中提供此点击监听器更有意义。这就是我们创建 setImageClickListener()
方法的原因。
我们将在第 4 步中使用 setImageClickListener()
。
public class ImageViewPreference extends Preference {
private ImageView imageView;
View.OnClickListener imageClickListener;
public ImageViewPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
//onBindViewHolder() will be called after we call setImageClickListener() from SettingsFragment
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
imageView = (ImageView)holder.findViewById(R.id.image);
imageView.setOnClickListener(imageClickListener);
}
public void setImageClickListener(View.OnClickListener onClickListener)
{
imageClickListener = onClickListener;
}
}
3 - 在您的 preference.xml
文件中添加这个新 class 的条目
现在将这个新 class 添加到您的 preference.xml
并使用 app:layout
属性设置其布局。
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<com.example.preferencefragmentsample.ImageViewPreference
app:key="image_preference"
app:layout="@layout/custom_layout" />
<Preference
app:key="notifications"
app:title="Notifications"
app:summary="Enable or disable notifications"
app:icon="@drawable/ic_notifications_24dp"
app:iconSpaceReserved="false"
/>
<Preference
app:key="feedback"
app:summary="Get to know the developer"
app:title="About"
app:icon="@drawable/ic_info_outline_24dp"/>
</PreferenceScreen>
4 - 在您的 SettingsFragment
现在只需使用 findPreference()
获取对 ImageViewPreference
的引用,方法是将您在 preference.xml
.
之后只需调用 setImageClickListener()
并在点击时提供您想要的任何功能。例如,我只是祝酒显示 "Image Clicked"
public class SettingsFragment extends PreferenceFragmentCompat {
ImageViewPreference imageViewPreference;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.prefs,rootKey);
imageViewPreference = (ImageViewPreference) findPreference("image_preference");
if (imageViewPreference != null)
imageViewPreference.setImageClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do whatever you want on image click here
Toast.makeText(getContext(), "Image Clicked", Toast.LENGTH_SHORT).show();
}
});
}
}
最终输出
更新:从 Firebase 云存储加载图像
NOTE: I haven't had the time to actually test and run this. This is just to give you a flow of how to do it. But I have carefully checked and everything seems fine and it should run as expected. I'll leave some minor changes to you if there are some errors regarding firebase or converting from File to Bitmap.
首先修改 ImageViewPreference
class 以便它可以接收位图并将位图应用到 ImageView
。它类似于我们收到 onClickListener
并将其应用于 ImageView
。
public class ImageViewPreference extends Preference {
private ImageView imageView;
private Bitmap imageBitmap;
View.OnClickListener imageClickListener;
public ImageViewPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
//onBindViewHolder() will be called after we call setImageClickListener() and setBitmap() from SettingsFragment
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
imageView = (ImageView)holder.findViewById(R.id.image);
imageView.setOnClickListener(imageClickListener);
imageView.setImageBitmap(imageBitmap);
}
public void setImageClickListener(View.OnClickListener onClickListener)
{
imageClickListener = onClickListener;
}
public void setBitmap(Bitmap bitmap)
{
imageBitmap = bitmap;
}
}
现在假设您已经按照文档配置了 firebase 云存储。使用 getFile()
方法从 firebase 云存储中检索本地 File
对象中的图像,并将该文件对象转换为位图。之后只需使用我们之前创建的 setBitmap()
方法将该位图发送到 ImageViewPreference
。
public class SettingsFragment extends PreferenceFragmentCompat {
private Bitmap imageBitmap;
ImageViewPreference imageViewPreference;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.prefs,rootKey);
//Get your image in a local file and convert it into bitmap
StorageReference storageRef = FirebaseStorage.getInstance().getReference().child("images/yourImage.jpg");
File localFile = File.createTempFile("myImage", "bmp");
storageRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
//Convert File to Bitmap
imageBitmap = BitmapFactory.decodeFile(localFile.getAbsolutePath());
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
// Handle any errors
}
});
imageViewPreference = (ImageViewPreference) findPreference("image_preference");
if (imageViewPreference != null)
{
imageViewPreference.setImageClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do whatever you want on image click here
Toast.makeText(getContext(), "Image Clicked", Toast.LENGTH_SHORT).show();
}
});
//Send the downloaded bitmap to ImageViewPreference
imageViewPreference.setBitmap(imageBitmap);
}
}
}