主界面的UI与设计
现在一般的项目都是底部几个按钮对应这几个fragment这种情况,这种大体上可以有2种写法
- FragmentTabHost/(RadiuGroup+RadiuButton)等等一些底部按钮+Fragment来展示
- 一些底部按钮+ViewPager+Fragment来实现
这两种我个人更喜欢使用的是第二种,并且在最近的项目中也是用第二种方式来实现的,如果产品说底部按钮对应的页面是不能够滑动的,那么两种没什么区别,(viewPager可以禁止滑动来实现)可后来如果产品又说需要滑动了,那如果用第一种实现的就傻了,而第二种默认就是可以滑动的只需要简单的修改一下就可以
public class ViewPagerMain extends ViewPager{
private boolean mIsScroll=true;//通过这个值来判断是否需要禁止滑动
public ViewPagerMain(Context context) {
super(context);
}
public ViewPagerMain(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mIsScroll==true){
return super.onInterceptTouchEvent(ev);
}else{
return mIsScroll;
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mIsScroll==true){
return super.onTouchEvent(ev);
}else{
return mIsScroll;
}
}
public void setIsScroll(boolean isScroll){
mIsScroll = isScroll;
}
}
至于底部的那些按钮我并没有使用上面的一些Android原生控件,而是通过
布局文件自己摆放,我个人认为这样的话扩展性更高一些,当然这只是一部分原因后面的代码大家可以看到这么写的好处
底部xml
<LinearLayout
android:id="@+id/main_bottom_root"
android:layout_width="match_parent"
android:layout_height="@dimen/y96"
android:background="#fff"
>
<LinearLayout
android:id="@+id/home_root"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/iv_home"
style="@style/bottom_iv"
android:background="@drawable/home_selector"
/>
<TextView
android:id="@+id/tv_home"
style="@style/main_tv"
android:text="晒e晒"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/rb_message"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/iv_message"
style="@style/bottom_iv"
android:background="@drawable/message_selector" />
<TextView
android:id="@+id/tv_message"
style="@style/main_tv"
android:text="消息"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/rb_service"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
style="@style/bottom_iv"
android:background="@drawable/service_selector"
android:id="@+id/iv_service" />
<TextView
android:id="@+id/tv_service"
style="@style/main_tv"
android:text="服务"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/rb_find"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/iv_find"
style="@style/bottom_iv"
android:background="@drawable/find_selector" />
<TextView
android:id="@+id/tv_find"
style="@style/main_tv"
android:text="发现"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/rb_my"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/iv_mine"
style="@style/bottom_iv"
android:background="@drawable/mine_selector" />
<TextView
android:id="@+id/tv_mine"
style="@style/main_tv"
android:text="我的"
/>
</LinearLayout>
</LinearLayout>
/**
* 监听底部按钮的切换状态,mMainBottomRoot为底部按钮的根布局,这样封装的话如果底部按钮的数量有变动
* 这段代码不用发生什么变动,而且下一个项目用到的话直接复制粘贴
private void setBottomListener() {
int childCount = mMainBottomRoot.getChildCount();
for (int i = 0; i <childCount ; i++) {
//获得子布局,为每个子view设置点击事件
LinearLayout child = (LinearLayout) mMainBottomRoot.getChildAt(i);
child.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//通过mMainBottomRoot来获得点击view对应的索引值
int indexOfChild = mMainBottomRoot.indexOfChild(view);
//根据索引来改变UI效果
changeUI(indexOfChild);
//viewPager也跳到对应的Fragment中
mViewpagerMain.setCurrentItem(indexOfChild, false);
}
});
}
}
/**
* 当viewPager切换的时候更改底部按钮的UI状态
* @param position
*/
private void changeUI(int position) {
for (int i = 0; i <mMainBottomRoot.getChildCount() ; i++) {
if (i==position){
setEnable(mMainBottomRoot.getChildAt(i),false);
}else{
setEnable(mMainBottomRoot.getChildAt(i),true);
}
}
}
/**
* 更改底部按钮UI状态,如果是view直接setEnable,如果是viewGroup递归遍历其中的view setEnable
* @param childAt
* @param b
*/
private void setEnable(View childAt, boolean b) {
childAt.setEnabled(b);
if (childAt instanceof ViewGroup){
for (int i = 0; i < ((ViewGroup) childAt).getChildCount(); i++) {
setEnable(((ViewGroup) childAt).getChildAt(i),b);
}
}
}
至于Fragment 我这里对Fragment展示的布局做了进一步封装,因为现在项目的主界面大体上不外呼刚进来时候弹个ProgressBar,DialogFragmen等与用户进行交互,当数据请求回来再隐藏销毁,如果数据请求失败再展示个失败的界面
这里我对它又进行了一次封装,不仅减少了代码的书写也加强了扩展性和维护性
/**
* BaseFragment
*/
public abstract class MyBaseFragment extends Fragment {
protected Context context;
protected StateLayout stateLayout;
protected boolean isFirst = true;
protected boolean isPrepared;
private Unbinder mUnbinder;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
context = getActivity();
//防止Fragment重复加载
if (stateLayout == null) {
// 说明这个Fragemnt的onCreateView方法是第一次执行
View view = getContentView();
mUnbinder = ButterKnife.bind(this, view);
//对Fragment展示的布局进一步封装
stateLayout = StateLayout.newInstance(context, view);
initView();
initListener();
//
isPrepared = true;
} else {
ViewGroup parent = (ViewGroup) stateLayout.getParent();
if (parent != null) {
parent.removeView(stateLayout);
}
}
return stateLayout;
}
/**
* Fragment当前状态是否可见
*/
protected boolean isVisible;
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
isVisible = true;
LogUtil.e(getClass().getName()+"__________setUserVisibleHint");
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
@Override
public void onResume() {
super.onResume();
LogUtil.e(getClass().getName()+"__________onResume");
onVisible();
}
/**
* 对initData再进一步的封装
*/
protected void onVisible() {
//保证ViewPager能够实现懒加载的方式并保证只有第一次进入这个Fragment的时候才进行数据的加载
LogUtil.e("isFirst _____________" + isFirst);
LogUtil.e("isVisible _____________" + isVisible);
LogUtil.e("isPrepared _____________" + isPrepared);
if (!isFirst || !isVisible || !isPrepared) {
return;
}
initData();
isFirst = false;
}
/**
* 不可见
*/
protected void onInvisible() {
}
/**
* 查找View,增加这个方法是为了略强转
*
* @param id
* @return
*/
@SuppressWarnings("unchecked")
public <T> T findView(int id) {
T view = (T) stateLayout.findViewById(id);
return view;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mUnbinder!=null){
mUnbinder.unbind();
}
}
/**
* 返回Fragment自己的名称
*/
protected CharSequence getTitle(){
return getClass().getName();
};
/**
* 初始化View相关的代码写在这个方法中
*/
public abstract void initView();
/**
* 初始化Listener的代码写在这个方法中
*/
public abstract void initListener();
/**
* 初始化数据的代码写在这个方法中
*/
public abstract void initData();
/**
* 返回正常的界面想要展示的View或View的Id
*/
public abstract View getContentView();
}
public class StateLayout extends FrameLayout {
private View loadingView;
private View failView;
private View emptyView;
private View contentView;
public StateLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 创建一个StateLayout实现
* @param contentView 正常想要展示的View
*/
public static StateLayout newInstance(Context context, View contentView) {
StateLayout stateLayout = (StateLayout) LayoutInflater.from(context).inflate(R.layout.state_layout, null);
stateLayout.contentView=contentView;
// StateLayout inflate之后就有3个状态的View了,还需要第四种状态
stateLayout.addView(contentView);
//当添加完成后暂时给隐藏掉
contentView.setVisibility(View.GONE);
return stateLayout;
}
/**
* 渲染完毕后展示获取view对象
*/
@Override
protected void onFinishInflate() {
loadingView = findViewById(R.id.loadingView);
failView = findViewById(R.id.failView);
emptyView = findViewById(R.id.emptyView);
showLoadingView();
}
/** 显示正在加载的View */
public void showLoadingView() {
showView(loadingView);
}
/** 显示失败的View */
public void showFailView() {
showView(failView);
}
/** 显示加载为空的View */
public void showEmptyView() {
showView(emptyView);
}
/** 显示正常界面的View */
public void showContentView() {
showView(contentView);
}
/**
* 显示指定的View,并且隐藏其它的View
* @param view 指定要显示的View
*/
private void showView(View view) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i); //
child.setVisibility(view == child ? View.VISIBLE : View.GONE);
}
}
}
具体的我就不细说了,
有需要的话可以
下来看看https://github.com/wangrun1992/MainUiFrame