神马笔记最新版本下载:【神马笔记 版本1.5.0——笔名功能.apk】
随着软件功能的增加,不可避免地会加入越来越多的设置项。如何管理不断增加的设置项?
首先,必修便于创建,修改,删除,并且只需要改动配置项,而不用对界面进行太大的修改。
其次,子设置界面必须与主设置界面保持风格一致。
实现设置界面的方式有很多,可以选择任意的容器和控件进行组合,从而实现设置界面。
但是设置界面有其特殊性。
设置界面通常是有多个设置项组成,每一个设置项又由键值对构成。多个设置项可以组合成一个设置组,设置组之间由分割线区分开。其组成方式大概如下结构。
从以上结构来看,设置界面便是一组设置项的列表。列表界面自然是使用RecyclerView来实现。
定义设置项UI的组成。
public class BaseSettingItem<T> {
public static final int DIVIDER_NONE = 0;
public static final int DIVIDER_NAME = 1;
String id; // 唯一ID
@DrawableRes int iconResId; // 图标资源
ColorStateList iconTintList; // 图标Tint
CharSequence name; // 名称
CharSequence text; // 文本
boolean chevron; // 是否显示chevron
Consumer<T> consumer; // 列表项处理点击事件
T userObject; // 用户数据
boolean dividerVisible; // 是否显示分割线
int dividerType; // 分割线的显示方式
}
定义基础设置项的布局。基础布局包括图标、名称、箭头3个部分组成。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/settingItemHeight"
android:background="@color/colorSettingItemBackground"
android:paddingLeft="?listPreferredItemPaddingLeft"
android:paddingRight="?listPreferredItemPaddingRight"
android:gravity="center_vertical"
android:foreground="?selectableItemBackground">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="?listPreferredItemPaddingRight"/>
<TextView
android:id="@+id/tv_name"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Menu"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/iv_chevron"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_chevron_right_white_24dp"
android:tint="@color/colorChevron"/>
LinearLayout>
RecyclerView的ViewHolder实现。
public class BaseSettingViewHolder<T extends BaseSettingItem> extends BridgeViewHolder<T> implements SectionDividerDecoration.Adapter {
public static final int LAYOUT_RES_ID = R.layout.layout_setting_list_item;
ImageView iconView;
TextView nameView;
TextView textView;
ImageView chevronView;
@Keep
public BaseSettingViewHolder(View itemView) {
super(itemView);
}
@Override
public int getLayoutResourceId() {
return LAYOUT_RES_ID;
}
@Override
public void onViewCreated(@NonNull View view) {
view.setOnClickListener(this::onItemClick);
this.iconView = view.findViewById(R.id.iv_icon);
this.nameView = view.findViewById(R.id.tv_name);
this.textView = view.findViewById(R.id.tv_text);
this.chevronView = view.findViewById(R.id.iv_chevron);
if (iconView != null) {
if (iconView.getOutlineProvider() != null) {
iconView.setClipToOutline(true);
}
}
}
@Override
public void onBind(T item, int position) {
if (iconView != null) {
if (item.getIcon() > 0) {
iconView.setImageResource(item.getIcon());
iconView.setVisibility(View.VISIBLE);
} else {
iconView.setImageDrawable(null);
iconView.setVisibility(View.GONE);
}
iconView.setImageTintList(item.getIconTintList());
}
if (nameView != null) {
nameView.setText(item.getName());
}
if (textView != null) {
textView.setText(item.getText());
}
if (chevronView != null) {
chevronView.setVisibility(item.isChevron()? View.VISIBLE: View.GONE);
}
}
protected void onItemClick(View view) {
T item = getItem();
if (item.getConsumer() != null) {
item.getConsumer().accept(item.getUserObject());
}
}
@Override
public int getMargin(SectionDividerDecoration decoration) {
int margin = 0;
int type = getItem().getDividerType();
if (type == BaseSettingItem.DIVIDER_NAME) {
if (nameView != null) {
margin = nameView.getLeft();
}
}
return margin;
}
@Override
public boolean isVisible(SectionDividerDecoration decoration) {
return getItem().isDividerVisible();
}
}
定义设置界面的抽象Fragment,所有设置界面均继承该类,子类必须实现以下2个抽象接口。
List createList()
创建设置项列表。
void buildAdapter(BridgeAdapter adapter)
构建适配器。
public abstract class BasePreferenceFragment extends Fragment {
SearchTitleBar titleBar;
RecyclerView recyclerView;
BridgeAdapter adapter;
SettingProvider provider;
SectionDividerDecoration dividerDecoration;
public BasePreferenceFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_preference, container, false);
}
@CallSuper
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
{
this.titleBar = view.findViewById(R.id.title_bar);
Toolbar toolbar = titleBar.getToolbar();
toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
toolbar.setNavigationOnClickListener(this::onNavigationClick);
}
{
this.recyclerView = view.findViewById(R.id.recycler_list_view);
LinearLayoutManager layout = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layout);
}
{
this.dividerDecoration = new SectionDividerDecoration(getActivity());
recyclerView.addItemDecoration(dividerDecoration);
}
}
@CallSuper
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
{
this.provider = new SettingProvider(this.createList());
}
{
this.adapter = new BridgeAdapter(getActivity(), provider);
this.buildAdapter(adapter);
}
{
recyclerView.setAdapter(adapter);
}
}
void onNavigationClick(View view) {
getActivity().onBackPressed();
}
void setTitle(CharSequence text) {
titleBar.setTitle(text);
}
<T> T getItem(String id) {
return provider.getItem(id);
}
int indexOf(Object object) {
return provider.indexOf(object);
}
void notifyItemChanged(Object object) {
int index = indexOf(object);
if (index >= 0) {
adapter.notifyItemChanged(index);
}
}
abstract List<BaseSettingItem> createList();
abstract void buildAdapter(BridgeAdapter adapter);
/**
*
*/
class SettingProvider implements BridgeAdapterProvider<BaseSettingItem> {
ArrayList<BaseSettingItem> list;
public SettingProvider(List<BaseSettingItem> list) {
this.list = new ArrayList<>(list);
}
<T> T getItem(String id) {
BaseSettingItem item = list.stream()
.filter(e -> e.getId().equals(id))
.findAny()
.orElse(null);
return (T)item;
}
int indexOf(Object object) {
int size = list.size();
for (int i = 0; i < size; i++) {
if (list.get(i) == object) {
return i;
}
}
return -1;
}
@Override
public BaseSettingItem get(int position) {
return list.get(position);
}
@Override
public int size() {
return list.size();
}
}
}
实现主设置界面。
List createList()
添加了3个设置项——ProfileSettingItem、ExplainSettingItem、BaseSettingItem。
void buildAdapter(BridgeAdapter adapter)
绑定了3种ViewHolder——ProfileSettingViewHolder、ExplainSettingItem、BaseSettingViewHolder。
public class SettingFragment extends BasePreferenceFragment {
static final String ID_PROFILE = "profile";
RequestResultManager requestResultManager;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestResultManager = new RequestResultManager();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
requestResultManager.onActivityResult(requestCode, resultCode, data);
}
@Override
List<BaseSettingItem> createList() {
List<BaseSettingItem> list = new ArrayList<>();
{
ProfileSettingItem item = new ProfileSettingItem(PreferenceEntity.obtain().getProfile());
item.setId(ID_PROFILE);
item.setConsumer((obj) -> {
RequestProfileDelegate delegate = new RequestProfileDelegate(this, (data) -> onProfileChanged());
requestResultManager.request(delegate);
});
list.add(item);
}
{
ExplainSettingItem item = new ExplainSettingItem("");
list.add(item);
}
{
BaseSettingItem item = new BaseSettingItem("关于神马笔记");
item.setIcon(R.drawable.ic_info_outline_white_24dp);
item.setIconTintList(getActivity(), R.color.colorIcon);
item.setConsumer((obj) -> {
String url = "http://andnext.club/whatsnote/help.html";
String args = "ts=" + System.currentTimeMillis();
url = url + "?" + args;
PackageUtils.startBrowser(getActivity(), Uri.parse(url));
});
list.add(item);
}
return list;
}
@Override
void buildAdapter(BridgeAdapter adapter) {
adapter.bind(ExplainSettingItem.class,
new BridgeBuilder(ExplainSettingViewHolder.class, ExplainSettingViewHolder.LAYOUT_RESOURCE_ID));
adapter.bind(ProfileSettingItem.class,
new BridgeBuilder(ProfileSettingViewHolder.class, ProfileSettingViewHolder.LAYOUT_RESOURCE_ID));
adapter.bind(BaseSettingItem.class,
new BridgeBuilder(BaseSettingViewHolder.class, BaseSettingViewHolder.LAYOUT_RES_ID));
}
}
笔名设置界面,该界面比较复杂。
List createList()
添加了9个设置项。
void buildAdapter(BridgeAdapter adapter)
绑定了5种ViewHolder。
public class ProfileFragment extends BasePreferenceFragment {
static final String ID_PROFILE = "profile";
static final String ID_VISION = "vision";
RequestResultManager requestResultManager;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestResultManager = new RequestResultManager();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
{
this.setTitle("笔名");
}
{
dividerDecoration.setDrawTop(false);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
requestResultManager.onActivityResult(requestCode, resultCode, data);
}
@Override
List<BaseSettingItem> createList() {
List<BaseSettingItem> list = new ArrayList<>();
{
ProfileSettingItem item = new ProfileSettingItem(PreferenceEntity.obtain().getProfile());
item.setId(ID_PROFILE);
item.setDividerVisible(false);
item.setConsumer((obj) -> requestPicture((file, sourceUri) -> {
ProfileEntity entity = PreferenceEntity.obtain().getProfile();
Uri targetUri = entity.nextPortraitUri();
RequestCropDelegate delegate = new RequestCropDelegate(this,
file,
sourceUri,
targetUri,
(uCrop) -> {
uCrop.withAspectRatio(1, 1);
UCrop.Options options = new UCrop.Options();
options.setCircleDimmedLayer(true);
options.setHideBottomControls(true);
options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
options.setCompressionQuality(60);
options.setShowCropGrid(false);
options.setShowCropFrame(false);
uCrop.withOptions(options);
},
(uri) -> setPortrait(uri));
requestResultManager.request(delegate);
}));
list.add(item);
}
{
ExplainSettingItem item = new ExplainSettingItem("");
list.add(item);
}
{
BaseSettingItem item = new BaseSettingItem("昵称");
item.setDividerType(BaseSettingItem.DIVIDER_NAME);
item.setChevron(true);
item.setConsumer((obj) -> {
RequestNameDelegate delegate = new RequestNameDelegate(this, (name) -> this.setName(name));
requestResultManager.request(delegate);
});
list.add(item);
}
{
BaseSettingItem item = new BaseSettingItem("个性签名");
item.setDividerType(BaseSettingItem.DIVIDER_NONE);
item.setChevron(true);
item.setConsumer((obj) -> {
RequestSignatureDelegate delegate = new RequestSignatureDelegate(this, (signature) -> this.setSignature(signature));
requestResultManager.request(delegate);
});
list.add(item);
}
{
ExplainSettingItem item = new ExplainSettingItem("");
item.setDividerVisible(false);
list.add(item);
}
{
TitleSettingItem item = new TitleSettingItem("个性图签");
list.add(item);
}
{
BaseSettingItem item = new BaseSettingItem("选取新的图片签名");
item.setDividerType(BaseSettingItem.DIVIDER_NAME);
item.setChevron(false);
item.setConsumer((obj) -> requestPicture((file, sourceUri) -> {
ProfileEntity entity = PreferenceEntity.obtain().getProfile();
Uri targetUri = entity.nextVisionUri();
RequestCropDelegate delegate = new RequestCropDelegate(this,
file,
sourceUri,
targetUri,
(uCrop) -> {
uCrop.withAspectRatio(1.f * ProfileEntity.VISION_WIDTH / ProfileEntity.VISION_HEIGHT, 1);
UCrop.Options options = new UCrop.Options();
options.setCircleDimmedLayer(false);
options.setHideBottomControls(true);
options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
options.setCompressionQuality(60);
options.setShowCropGrid(false);
options.setShowCropFrame(false);
uCrop.withOptions(options);
},
(uri) -> setVision(uri));
requestResultManager.request(delegate);
}));
list.add(item);
}
{
PictureSettingItem item = new PictureSettingItem(
PreferenceEntity.obtain().getProfile().getVisionUri(),
ProfileEntity.VISION_WIDTH, ProfileEntity.VISION_HEIGHT);
item.setId(ID_VISION);
item.setErrorResId(R.drawable.ic_profile_vision);
list.add(item);
}
{
ExplainSettingItem item = new ExplainSettingItem("以图片方式分享笔记时,将显示图片签名。");
item.setDividerVisible(false);
list.add(item);
}
return list;
}
@Override
void buildAdapter(BridgeAdapter adapter) {
adapter.bind(TitleSettingItem.class,
new BridgeBuilder(TitleSettingViewHolder.class, TitleSettingViewHolder.LAYOUT_RESOURCE_ID));
adapter.bind(ExplainSettingItem.class,
new BridgeBuilder(ExplainSettingViewHolder.class, ExplainSettingViewHolder.LAYOUT_RESOURCE_ID));
adapter.bind(ProfileSettingItem.class,
new BridgeBuilder(MasterSettingViewHolder.class, MasterSettingViewHolder.LAYOUT_RESOURCE_ID));
adapter.bind(BaseSettingItem.class,
new BridgeBuilder(BaseSettingViewHolder.class, BaseSettingViewHolder.LAYOUT_RES_ID));
adapter.bind(PictureSettingItem.class,
new BridgeBuilder(PictureSettingViewHolder.class, PictureSettingViewHolder.LAYOUT_RES_ID));
}
}
~荒城临古渡~落日满秋山~