安卓前端UI一些有用的小技巧
EditText的一键清除小x
很多软件在编辑框处都有一键清除的按钮,这里介绍一下其实现方式
xml文件添加如下,使得清除按钮位于EditText的最右方
<EditText
android:id="@+id/login_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/login_username_text"
android:gravity="center"
android:hint="请输入用户名"/>
<Button
android:id="@+id/login_username_clear"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginRight="5dp"
android:background="@mipmap/clear"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@id/login_username"
app:layout_constraintRight_toRightOf="@id/login_username"
app:layout_constraintTop_toTopOf="@id/login_username" />
然后就是在java文件onCreate函数中实现逻辑了,这里我们所用到的控件为TextWatcher
private EditText login_username;
private Button login_username_clear;
private TextWatcher login_username_watcher;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_register);
login_username = (EditText)findViewById(R.id.login_username);
login_username_clear = (Button)findViewById(R.id.login_username_clear);
login_username.addTextChangedListener(login_username_watcher);
login_username_watcher = new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void beforeTextChanged(CharSequence s, int start, int count,int after) {}
public void afterTextChanged(Editable s) {
login_password.setText("");
if(s.toString().length()>0){
login_username_clear.setVisibility(View.VISIBLE);
}else{
login_username_clear.setVisibility(View.INVISIBLE);
}
}
};
}
这样就实现了一键清除效果按钮了
自定义Toolbar实现logo和小组件
我使用Toolbar组件来实现了logo和APP名称的显示,同时还在右侧增加了小组件以便于功能拓展
首先要把原有的ActionBar删除,这里需要修改AndriodManifest文件
<activity
android:name=".MainPartActivity"
android:theme="@style/AppTheme" />
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- toolbar(actionbar)颜色 -->
<item name="colorPrimary">@color/gray</item>
<!-- 状态栏颜色 -->
<item name="colorPrimaryDark">@android:color/darker_gray</item>
<!-- 窗口的背景颜色 -->
<item name="android:windowBackground">@color/white</item>
<item name="actionOverflowMenuStyle">@style/MenuStyle</item>
</style>
删除了之后,就可以在xml文件中加入自定义的Toolbar了
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/colorPrimary"
android:background="@color/Blue"
app:navigationIcon="@mipmap/logo"
app:popupTheme="@style/PopWindowBackgroundStyle"
app:theme="@style/PopWindowStyle"
app:title="易闲圈"
app:titleTextColor="@color/black" />
其中的PopWindowBackgroundStyle如下
<style name="PopWindowStyle" parent="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<!--字体和图标的颜色-->
<item name="android:textColorPrimary">@color/black</item>
</style>
随后仍然是修改java文件
private Toolbar toolbar;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_part);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
这里的main_menu就是自定义的右侧功能组文件,可以选择添加自己想要的功能,这里我定义了一个系统自带的搜索按钮和一个自定义的按钮
<?xml version="1.0" encoding="utf-8"?>
<menu android:name="menu1" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/search"
android:title="搜索框"
android:icon="@mipmap/search"
app:showAsAction="always"
app:actionViewClass="android.support.v7.widget.SearchView" />
<item
android:icon="@mipmap/icon_add"
app:showAsAction="always"
android:title="添加"
app:actionProviderClass="com.example.asus.earingmoney.adapter.PlusActionProvider"/>
</menu>
PlusActionProvider类用于自定义新按钮的功能
public class PlusActionProvider extends ActionProvider {
/**
* Creates a new instance.
*
* @param context Context for accessing resources.
*/
private Context context;
public PlusActionProvider(Context context) {
super(context);
this.context = context;
}
@Override
public View onCreateActionView() {
return null;
}
@Override
public void onPrepareSubMenu(SubMenu subMenu) {
subMenu.clear();
subMenu.add(("新建跑腿任务"))
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(getContext(),creat_errand_activity.class);
getContext().startActivity(intent);
return true;
}
});
subMenu.add(("新建问卷任务"))
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(getContext(),createQuestionare.class);
getContext().startActivity(intent);
return true;
}
});
}
@Override
public boolean hasSubMenu() {
return true;
}
}
使用ViewPager和RadioGroup实现多页面滑动功能
三个界面支持点击下方按钮切换或滑动切换
首先要明白的是这三个界面都是在同一个activity下,其中的页面内容可以通过修改ViewPager中绑定的Fragment来实现,上方的Toolbar则可以通过如上一个话题的onCreateOptionsMenu函数来实现修改
xml文件修改如下
<android.support.v4.view.ViewPager
android:id="@+id/fragment_vp"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintBottom_toTopOf="@+id/tabs_rg"/>
<RadioGroup
android:id="@+id/tabs_rg"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:background="#dcdcdc"
android:orientation="horizontal"
android:weightSum="3"
app:layout_constraintBottom_toBottomOf="parent"
android:paddingTop="5dp">
<RadioButton
android:id="@+id/main_tab"
android:checked="true"
android:text="首页"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_weight="1"
android:button="@null"
android:textColor="@color/radiobutton_textcolor"
android:drawableTop="@drawable/tab_main_selector"
android:gravity="center"/>
<RadioButton
android:id="@+id/tasks_tab"
android:text="任务"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_weight="1"
android:button="@null"
android:textColor="@color/radiobutton_textcolor"
android:drawableTop="@drawable/tab_tasks_selector"
android:gravity="center"/>
<RadioButton
android:id="@+id/me_tab"
android:text="我的"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_weight="1"
android:button="@null"
android:textColor="@color/radiobutton_textcolor"
android:drawableTop="@drawable/tab_me_selector"
android:gravity="center"/>
</RadioGroup>
activity页面如下
private ViewPager fragment_vp;
private RadioGroup tabs_rg;
private List<Fragment> fragments;
private FragmentPagerAdapter adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_part);
fragment_vp = findViewById(R.id.fragment_vp);
tabs_rg = findViewById(R.id.tabs_rg);
fragments = new ArrayList<>(3);
fragments.add(MainFragment.newInstance("首页"));
fragments.add(TasksFragment.newInstance("任务"));
fragments.add(MeFragment.newInstance("我的"));
adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments);
fragment_vp.setAdapter(adapter);
fragment_vp.addOnPageChangeListener(mPageChangeListener);
tabs_rg.setOnCheckedChangeListener(mOnCheckedChangeListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
fragment_vp.removeOnPageChangeListener(mPageChangeListener);
}
private ViewPager.OnPageChangeListener mPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
RadioButton radioButton = (RadioButton) tabs_rg.getChildAt(position);
radioButton.setChecked(true);
}
@Override
public void onPageScrollStateChanged(int state) {
}
};
private RadioGroup.OnCheckedChangeListener mOnCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
for (int i = 0; i < group.getChildCount(); i++) {
if (group.getChildAt(i).getId() == checkedId) {
fragment_vp.setCurrentItem(i);
if(headerUri != null)
{
CircleImageView btn = findViewById(R.id.headerPic);
if(btn == null)
{
return;
}
btn.setImageURI(headerUri);
}
if(sex == Constants.FEMALE)
{
ImageView sexImage = findViewById(R.id.sexImage);
if(sexImage == null)
return;
sexImage.setImageResource(R.mipmap.girl);
}
else
{
ImageView sexImage = findViewById(R.id.sexImage);
if(sexImage == null)
return;
sexImage.setImageResource(R.mipmap.boy);
}
return;
}
}
}
};
private class MyFragmentPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mList;
public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.mList = list;
}
@Override
public Fragment getItem(int position) {
return this.mList == null ? null : this.mList.get(position);
}
@Override
public int getCount() {
return this.mList == null ? 0 : this.mList.size();
}
}
最后再分别完成各个Fragment的内容就可以实现页面切换了
使用Spinner实现Listview的分类筛选和顺序显示功能
xml文件比较简单,由多个Spinner构成即可
<Spinner
android:id="@+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
java文件如下,由于我是在Fragment中实现,所以会和在Activity中实现有所不同
public class MainFragment extends Fragment {
private Spinner spinner1, spinner2, spinner3, spinner4;
private List<Mission> missionslist = new ArrayList<Mission>();//missionslist为显示的内容,
private List<Mission> totallist = new ArrayList<Mission>(); //totallist为所有mission内容,ques_list和err_list分别为问卷任务和跑腿任务
private List<Mission> questionare_missionslist = new ArrayList<Mission>();
private List<Mission> errand_missionslist = new ArrayList<Mission>();
private String[] mItems1,mItems2,mItems3,mItems4;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.main_fragment, container, false);
setHasOptionsMenu(true);
spinner1 = rootView.findViewById(R.id.spinner1);
spinner2 = rootView.findViewById(R.id.spinner2);
spinner3 = rootView.findViewById(R.id.spinner3);
spinner4 = rootView.findViewById(R.id.spinner4);
mItems1 = getResources().getStringArray(R.array.spin1);
mItems2 = getResources().getStringArray(R.array.spin2);
mItems3 = getResources().getStringArray(R.array.spin3);
mItems4 = getResources().getStringArray(R.array.spin4);
ArrayAdapter<String> adapter1=new ArrayAdapter<String>(getActivity(),android.R.layout.simple_spinner_dropdown_item, mItems1);
ArrayAdapter<String> adapter2=new ArrayAdapter<String>(getActivity(),android.R.layout.simple_spinner_dropdown_item, mItems2);
ArrayAdapter<String> adapter3=new ArrayAdapter<String>(getActivity(),android.R.layout.simple_spinner_dropdown_item, mItems3);
ArrayAdapter<String> adapter4=new ArrayAdapter<String>(getActivity(),android.R.layout.simple_spinner_dropdown_item, mItems4);
adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter3.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter4.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//绑定 Adapter到控件
spinner1.setAdapter(adapter1);
spinner2.setAdapter(adapter2);
spinner3.setAdapter(adapter3);
spinner4.setAdapter(adapter4);
iniSpiner();
}
private void iniSpiner(){//用于排序、筛选
spinner1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { //对问卷或跑腿任务进行筛选
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(position == 0){
missionslist.clear();
missionslist.addAll(totallist);
}
else if(position == 1){
missionslist.clear();
missionslist.addAll(questionare_missionslist);
}
else{
missionslist.clear();
missionslist.addAll(errand_missionslist);
}
adapter.notifyDataSetChanged();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){ //对酬劳进行排序
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(position == 0){
MissionsSortUtil.sortById(missionslist);
}
else if(position == 1){
MissionsSortUtil.sortByPriceUp(missionslist);
}
else {
MissionsSortUtil.sortByPriceDown(missionslist);
}
adapter.notifyDataSetChanged();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner3.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){ //对截止时间进行排序
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(position == 0){
MissionsSortUtil.sortById(missionslist);
}
else if(position == 1){
MissionsSortUtil.sortByTimeUp(missionslist);
}
else {
MissionsSortUtil.sortByTimeDown(missionslist);
}
adapter.notifyDataSetChanged();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
}
上面的iniSpiner函数仅是我所需要的功能,大家可根据自己的需求自行更改
还有上面的arrays文件则是用来显示spinner下拉后的内容
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="spin1">
<item>所有类型</item>
<item>问卷任务</item>
<item>跑腿任务</item>
</string-array>
<string-array name="spin2">
<item>任务酬劳</item>
<item>升序</item>
<item>降序</item>
</string-array>
<string-array name="spin3">
<item>截止时间</item>
<item>时间充裕</item>
<item>时间急迫</item>
</string-array>
<string-array name="spin4">
<item>tag</item>
<item>tag1</item>
<item>tag2</item>
</string-array>
<string-array name="missionOrTask">
<item>我发布的</item>
<item>我接受的</item>
</string-array>
<string-array name="completeness">
<item>全部</item>
<item>已完成</item>
<item>未完成</item>
<item>已过期</item>
</string-array>
</resources>
上面代码中的几个MissionsSortUtil.sortBy函数也是我自己定义的排序函数,大家也可以根据自己Listview中的定义的属性来进行排序
public class MissionsSortUtil {
static Comparator<Mission> missionComparatorById = new Comparator<Mission>() {
@Override
public int compare(Mission lhs, Mission rhs) {
if(lhs.getMissionId() > rhs.getMissionId())
return 1;
return -1; //注意此处不是0
}
};
static Comparator<Mission> missionComparatorByPriceUp = new Comparator<Mission>() {
@Override
public int compare(Mission lhs, Mission rhs) {
if(lhs.getMoney() < rhs.getMoney())
return 1;
return -1; //注意此处不是0
}
};
static Comparator<Mission> missionComparatorByPriceDown = new Comparator<Mission>() {
@Override
public int compare(Mission lhs, Mission rhs) {
if(lhs.getMoney() > rhs.getMoney())
return 1;
return -1; //注意此处不是0
}
};
static Comparator<Mission> missionComparatorByTimeUp = new Comparator<Mission>() {
@Override
public int compare(Mission lhs, Mission rhs) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
if(sdf.parse(lhs.getDeadLine()).getTime() < sdf.parse(rhs.getDeadLine()).getTime())
return 1;
} catch (ParseException e) {
e.printStackTrace();
}
return -1;
}
};
static Comparator<Mission> missionComparatorByTimeDown = new Comparator<Mission>() {
@Override
public int compare(Mission lhs, Mission rhs) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
if(sdf.parse(lhs.getDeadLine()).getTime() > sdf.parse(rhs.getDeadLine()).getTime())
return 1;
} catch (ParseException e) {
e.printStackTrace();
}
return -1;
}
};
public static void sortById(List<Mission> missionsArray) {
Collections.sort(missionsArray, missionComparatorById);
}
public static void sortByPriceUp(List<Mission> missionsArray) {
Collections.sort(missionsArray, missionComparatorByPriceUp);
}
public static void sortByPriceDown(List<Mission> missionsArray) {
Collections.sort(missionsArray, missionComparatorByPriceDown);
}
public static void sortByTimeUp(List<Mission> missionsArray) {
Collections.sort(missionsArray, missionComparatorByTimeUp);
}
public static void sortByTimeDown(List<Mission> missionsArray) {
Collections.sort(missionsArray, missionComparatorByTimeDown);
}
}
使用SwipeRefreshLayout更新Listview
当我们使用Listview来显示我们从后台拿到的数据时,我们可能会想要有一个功能使得数据能够在想要的时候进行刷新,于是我就使用SwipeRefreshLayout实现了下拉刷新效果
xml文件更改如下
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/swipeLayout"
app:layout_constraintTop_toBottomOf="@id/spinner_list_2"
app:layout_constraintBottom_toBottomOf="parent">
<ListView
android:id = "@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:paddingLeft="10dp"
android:paddingRight="10dp">
</ListView>
</android.support.v4.widget.SwipeRefreshLayout>
java文件如下
swipeRefreshLayout = rootView.findViewById(R.id.swipeLayout);
swipeRefreshLayout.setSize(SwipeRefreshLayout.DEFAULT);
swipeRefreshLayout.setProgressViewEndTarget(true, 200);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
swipeRefreshLayout.setRefreshing(true);
getMissions();
}
});
其中的setRefreshing函数即让它显示搜索时的转圈圈效果,这个效果需要手动关闭,即在getMissions函数结尾加上swipeRefreshLayout.setRefreshing(false);即可
以上就是我对这次大项目所总结出的几个界面UI实用的小技巧,希望能够帮助到大家