1.我们只做的团原型如图,这个不是我自己编写的,看了别人的源码,收货了很多的东西!

特别是首页的制作,特别的不错,很值得我学习一哈首先我们来观看一下我们的主要的内成员

3.我们就开始从MainActivity开始解析这个整个工程吧!你们有很多的东西值得我们去吸收,在以后利用。

首先我们看一下主页的xml文件的定义是如何的进行的呢?

上面是为我们的FrametLayout;
下面是我们自己定义的控件类,仔细的想一哈,为什么要这么的弄呢?

package com.lee.privatecustom.activity;
import com.lee.privatecustom.R;
import com.lee.privatecustom.fragment.CategoryFragment;
import com.lee.privatecustom.fragment.CollectFragment;
import com.lee.privatecustom.fragment.HomeFragment;
import com.lee.privatecustom.fragment.SettingFragment;
import com.lee.privatecustom.utils.ConstantValues;
import com.lee.privatecustom.view.MyTabWidget;
import com.lee.privatecustom.view.MyTabWidget.OnTabSelectedListener;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
/**
* 导航页
*
*/
public class MainActivity extends FragmentActivity implements
OnTabSelectedListener {
private static final String TAG = "MainActivity";
private MyTabWidget mTabWidget;//底部的导航
private HomeFragment mHomeFragment;//主页
private CategoryFragment mCategoryFragment;//分类!
private CollectFragment mCollectFragment;
private SettingFragment mSettingFragment;
private int mIndex = ConstantValues.HOME_FRAGMENT_INDEX;//选中的到底是第几个按钮呢,这里就是个常数
private FragmentManager mFragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
initEvents();
}
private void init() {
mFragmentManager = getSupportFragmentManager();
mTabWidget = (MyTabWidget) findViewById(R.id.tab_widget);//底部的导航
}
private void initEvents() {
mTabWidget.setOnTabSelectedListener(this);
}
@Override
protected void onResume() {//ragment能与用户交互,当主activity处于resumed状态后执行,所以现在
//处于初始化的界面吧,让我们的下面的Tab,变色,以及红点的跳动
super.onResume();
onTabSelected(mIndex);
mTabWidget.setTabsDisplay(this, mIndex);
mTabWidget.setIndicateDisplay(this, mIndex, true);
}
@Override
public void onTabSelected(int index) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
hideFragments(transaction);
switch (index) {
case ConstantValues.HOME_FRAGMENT_INDEX:
if (null == mHomeFragment) {
mHomeFragment = new HomeFragment();
transaction.add(R.id.center_layout, mHomeFragment);
} else {
transaction.show(mHomeFragment);
}
break;
case ConstantValues.CATEGORY_FRAGMENT_INDEX:
if (null == mCategoryFragment) {
mCategoryFragment = new CategoryFragment();
transaction.add(R.id.center_layout, mCategoryFragment);
} else {
transaction.show(mCategoryFragment);
}
break;
case ConstantValues.COLLECT_FRAGMENT_INDEX:
if (null == mCollectFragment) {
mCollectFragment = new CollectFragment();
transaction.add(R.id.center_layout, mCollectFragment);
} else {
transaction.show(mCollectFragment);
}
break;
case ConstantValues.SETTING_FRAGMENT_INDEX:
if (null == mSettingFragment) {
mSettingFragment = new SettingFragment();
transaction.add(R.id.center_layout, mSettingFragment);
} else {
transaction.show(mSettingFragment);
}
break;
default:
break;
}
mIndex = index;
transaction.commitAllowingStateLoss();
}
private void hideFragments(FragmentTransaction transaction) {
if (null != mHomeFragment) {
transaction.hide(mHomeFragment);
}
if (null != mCategoryFragment) {
transaction.hide(mCategoryFragment);
}
if (null != mCollectFragment) {
transaction.hide(mCollectFragment);
}
if (null != mSettingFragment) {
transaction.hide(mSettingFragment);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// 自己记录fragment的位置,防止activity被系统回收时,fragment错乱的问题
// super.onSaveInstanceState(outState);
outState.putInt("index", mIndex);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// super.onRestoreInstanceState(savedInstanceState);
mIndex = savedInstanceState.getInt("index");
}
}

由于我们中间的是FrameLayout,我们每次显示的时候都是初始化在内存中,全部不显示就让他hide,这就是FragmentTransaction的管理过程,然后通过时候点击
判断显示什么,同时这里还增加了系统推出的处理方案,让他记住我么的mindex,每次回来的时候 还是在刚刚的那个界面上的
既然刚才我么已经谈到了我们的Tab的东西了,下面我们把Tabitem.xml文件贴一下吧,就是一个CheckTextView+ImageView(用来显示跳动的小圆点的!刚刚开始时看不到的
通过控制显示来完成我们的任务的!MyTabWidget.java
package com.lee.privatecustom.view;
import java.util.ArrayList;
import java.util.List;
import com.lee.privatecustom.R;
import com.lee.privatecustom.exception.CustomException;
import com.lee.privatecustom.utils.LogUtils;
import android.R.integer;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.LinearLayout;
/**
* 底部导航
*
* @author JetWang
*
*/
public class MyTabWidget extends LinearLayout {
private static final String TAG = "MyTabWidget";
private int[] mDrawableIds = new int[] { R.drawable.bg_home,
R.drawable.bg_category, R.drawable.bg_collect,
R.drawable.bg_setting };
// 存放底部菜单的各个文字CheckedTextView
private ListmCheckedList = new ArrayList();
// 存放底部菜单每项View
private ListmViewList = new ArrayList();
// 存放指示点
private ListmIndicateImgs = new ArrayList(); // 底部菜单的文字数组 private CharSequence[] mLabels; public MyTabWidget(Context context, AttributeSet attrs, int defStyle) { super(context, attrs,defStyle); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabWidget, defStyle, 0); // 读取xml中,各个tab使用的文字 mLabels = a.getTextArray(R.styleable.TabWidget_bottom_labels); if (null == mLabels || mLabels.length <= 0) { try { throw new CustomException("底部菜单的文字数组未添加..."); } catch (CustomException e) { e.printStackTrace(); } finally { LogUtils.i(TAG, MyTabWidget.class.getSimpleName() + " 出错"); } a.recycle();//必须得处理掉这个东西哟 return; } a.recycle(); // 初始化控件 init(context); } public MyTabWidget(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyTabWidget(Context context) { super(context); init(context); } /** * 初始化控件 */ private void init(final Context context) { this.setOrientation(LinearLayout.HORIZONTAL); this.setBackgroundResource(R.drawable.index_bottom_bar); LayoutInflater inflater = LayoutInflater.from(context); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); params.weight = 1.0f; params.gravity = Gravity.CENTER; /*让他们自动的分配自己的大小了*/ int size = mLabels.length; for (int i = 0; i < size; i++) { final int index = i; // 每个tab对应的layout final View view = inflater.inflate(R.layout.tab_item, null); final CheckedTextView itemName = (CheckedTextView) view .findViewById(R.id.item_name); itemName.setCompoundDrawablesWithIntrinsicBounds(null, context .getResources().getDrawable(mDrawableIds[i]), null, null); itemName.setText(mLabels[i]); /*使用其父类的消息,让图片画在我的下面文字的*/ // 指示点ImageView,如有版本更新需要显示 final ImageView indicateImg = (ImageView) view .findViewById(R.id.indicate_img); this.addView(view, params); // CheckedTextView设置索引作为tag,以便后续更改颜色、图片等 itemName.setTag(index); // 将CheckedTextView添加到list中,便于操作 mCheckedList.add(itemName); // 将指示图片加到list,便于控制显示隐藏 mIndicateImgs.add(indicateImg); // 将各个tab的View添加到list mViewList.add(view); view.setOnClickListener(new OnClickListener() {//每一个添加监听tab @Override public void onClick(View v) { // 设置底部图片和文字的显示 setTabsDisplay(context, index); if (null != mTabListener) { // tab项被选中的回调事件 mTabListener.onTabSelected(index); } } }); // 初始化 底部菜单选中状态,默认第一个选中 if (i == 0) { itemName.setChecked(true); itemName.setTextColor(Color.rgb(247, 88, 123)); view.setBackgroundColor(Color.rgb(240, 241, 242)); } else { itemName.setChecked(false); itemName.setTextColor(Color.rgb(19, 12, 14)); view.setBackgroundColor(Color.rgb(250, 250, 250)); } } } /** * 设置指示点的显示 * * @param context * @param position * 显示位置 * @param visible * 是否显示,如果false,则都不显示 */ public void setIndicateDisplay(Context context, int position, boolean visible) { int size = mIndicateImgs.size(); if (size <= position) { return; } ImageView indicateImg; for(int i=0;i

每次点击Tab,出发我们的View的点击事件,然后带动我们内部自定义的mTabListener.onTabSelected(index);,这使得我们MainActivity实现了这个接口回调这个函数
因此,会让我们的Fragment显示出来,会出发Resume事件,
mTabWidget.setTabsDisplay(this, mIndex);//让我么的tab的颜色进行设置
mTabWidget.setIndicateDisplay(this, mIndex, true);//设置小红点的隐藏和显示
其他的Fragment都差不多了,我们主要来说一下,我们的HomeFragment 和CategoryFrgment这两个算是比较的复杂的对象咯

首先来一下HomeFragment的xml文件吧!
最上面的是include 是一个三个图片两边的View.gone 中间的显示....这样的设计非常的棒,可以重复的利用而且可以在两边加上很多的有用的东西哟!
下面的是一个ViewPager,还有个我们自己定义的TopIndicator点击打开链接,在这里我曾经有过非常详细的解说过了!


这个可以非常好的理解一下,对于在外面的函数使用我们的接口,这是一个非常不错的选择,以后要经常的利用哦!

package com.lee.privatecustom.fragment;
import com.lee.privatecustom.R;
import com.lee.privatecustom.adapter.CateListAdapter;
import com.lee.privatecustom.fragment.AnimFragment.OnFragmentDismissListener;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class CategoryFragment extends BaseFragment implements
OnItemClickListener, OnClickListener, OnFragmentDismissListener {
private static final String TAG = "CategoryFragment";
private Activity mActivity;
private TextView mTitleTv;
// 左侧分类ListView
private ListView mCateListView;
private CateListAdapter mCateListAdapter;
private String[] mCategories;
private ImageView mCateIndicatorImg;
// 用于记录动画开始的位置
private int mFromY = 0;
private ImageButton mImageBtn;
public static CategoryFragment newInstance() {
CategoryFragment categoryFragment = new CategoryFragment();
return categoryFragment;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_category, container,
false);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViews(view);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mCategories = mActivity.getResources()
.getStringArray(R.array.cate_list);
mCateListAdapter = new CateListAdapter(mActivity, mCategories);
mCateListView.setAdapter(mCateListAdapter);
// 用于计算mCateIndicatorImg的高度
int itemHeight = calculateListViewItemHeight();
int w = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
mCateIndicatorImg.measure(w, h);
// 第一次进来设置indicator的位置
doAnimation(itemHeight / 2 - mCateIndicatorImg.getMeasuredHeight());
}
private void initViews(View view) {
mTitleTv = (TextView) view.findViewById(R.id.title_tv);
mTitleTv.setText(R.string.category);
mCateListView = (ListView) view.findViewById(R.id.cate_listview);
mCateListView.setOnItemClickListener(this);
mCateIndicatorImg = (ImageView) view
.findViewById(R.id.cate_indicator_img);
mImageBtn = (ImageButton) view.findViewById(R.id.image_btn);
mImageBtn.setOnClickListener(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onItemClick(AdapterViewparent, View view, int position,
long id) {
if (null != mCateListAdapter) {
mCateListAdapter.setSelectedPos(position);
}
int toY = view.getTop() + view.getHeight() / 2;//此时这个ItemView的中间的高度,为了显示跳转的变化
doAnimation(toY);
}
private void doAnimation(int toY) {
int cateIndicatorY = mCateIndicatorImg.getTop()
+ mCateIndicatorImg.getMeasuredHeight() / 2;
TranslateAnimation animation = new TranslateAnimation(0, 0, mFromY
- cateIndicatorY, toY - cateIndicatorY);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.setFillAfter(true);
animation.setDuration(400);
mCateIndicatorImg.startAnimation(animation);
mFromY = toY;
}
/*计算Listview的高度*/
private int calculateListViewItemHeight() {
ListAdapter listAdapter = mCateListView.getAdapter();
if (listAdapter == null) {
return 0;
}
int totalHeight = 0;
int count = listAdapter.getCount();
for (int i = 0; i < count; i++) {
View listItem = listAdapter.getView(i, null, mCateListView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
return totalHeight / count;
}
@Override
public String getFragmentName() {
return TAG;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.image_btn:
showAnimFragment();
break;
default:
break;
}
}
/**
* 显示侧边的动画fragment
*/
private void showAnimFragment() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.left_in, R.anim.right_out);
/**
* public abstract FragmentTransaction setCustomAnimations (int enter, int exit)
*Set specific animation resources to run for the fragments that are entering
* and exiting in this transaction. These animations will not be played when
*  popping the back stack.
*/
Fragment prev = getFragmentManager().findFragmentByTag("anim_fragment");
if (prev != null) {
ft.remove(prev);
}
AnimFragment animFragment = new AnimFragment(this);
ft.addToBackStack(null);
/*Add this transaction to the back stack.*/
ft.add(R.id.anim_fragment_layout, animFragment, "anim_fragment")
.commitAllowingStateLoss();
/*public abstract int commitAllowingStateLoss ()
* 像commit(),但允许提交保存在一个活动的执行状态。这是危险的
* ,因为承诺可能会丢失,如果需要从其状态后恢复活动,所以这应该只用于UI状态的情况下,
* 它是好的改变出人意料地在用户。
*/
}
/**
* 隐藏侧边动画fragment
*/
private void dismissAnimFragment() {
getFragmentManager().popBackStack();
}
@Override
public void onFragmentDismiss() {
dismissAnimFragment();
}
}

这里面的对于Listview的利用也不错哟!也是自定义,自适应。

下面的这个视图是


就是这个他让我们无法触摸了的节奏
package com.lee.privatecustom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
/**
* 点击不可透过的RelativeLayout
*/
public class CustomRelativeLayout extends RelativeLayout {
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRelativeLayout(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return true;
}
}
总结:说了很多,通过这次的学习很深的了解到了,我么你的自绘,自己重新创造控件给我们带来的想像的空间,这是多么的美好啊!good,job

自定义控件+ViewPage+Fragment....各种收获相关推荐

  1. ViewPage+Fragment的使用例子

    2013年9月6日Fragment学习 Fragment这个东西,我到现在才接触到,之前没有用到过,关于Fragment这个东西在官方文档已经介绍了非常清楚了,我还特地转载了官方API的中文翻译,在这 ...

  2. activity中fragment 返回键不退出_优雅地处理加载中(loading),重试(retry)和无数据(empty)等...

    LoadSir是一个高效易用,低碳环保,扩展性良好的加载反馈页管理框架,在加载网络或其他数据时候,根据需求切换状态页面,可添加自定义状态页面,如加载中,加载失败,无数据,网络超时,占位图,登录失效等常 ...

  3. Android多个fragment懒加载的坑(卡顿)

    在Android开发中,有很多种情况都是viewpage+fragment左右滑动进行布局的,例如下面的今日头条 在今日头条app上,我们可以看到,其顶部都是一栏的类型数据源,可滑动,可联动下面的vi ...

  4. Fragment 懒加载

    为何懒加载 在很多 App 都会有ViewPage + Fragment 的基本组合,但是众所周知 viewPager 的 预加载机制,即使设置函数 setOffscreenPageLimit(0) ...

  5. Android系统(74)--- 从零实现灵活且可高度定制的Android图片选择架构

    从零实现灵活且可高度定制的Android图片选择架构 https://www.jianshu.com/u/df76f81fe3ff 前言 这是我花费了数月闲暇时间从零开始写的一个库,在这期间,我学习到 ...

  6. android源码大放送啦(实战开发必备)

    文件夹 PATH 列表 卷序列号为 000A-8F50 E:. │  javaapk.com文件列表生成工具.bat │  使用说明.txt │  免费下载更多源码.url │  目录列表.txt │ ...

  7. Android开发必备(干货源码放送大)

    Android源码大放送(实战开发必备) 文件夹 PATH 列表 │  javaapk.com文件列表生成工具.bat │  使用说明.txt │  免费下载更多源码.url │  目录列表.txt ...

  8. MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现

    Demo补充中(UpDating):https://github.com/JinBoy23520/MPAndroidChartDemoByJin 本文出自:http://blog.csdn.net/d ...

  9. 月营收同比 10 倍增长,神策分析 1.8 推出英文版

    数据驱动力正在帮助企业进行数据资产的沉淀与应用.在市场体量与客户需求高速增长的态势下,数据赋予企业管理者衡量企业发展健康度和进行科学决策的领导力. 企业级服务根源于客户需求,神策分析将用户需求融入产品 ...

  10. Android典型界面设计(3)——访网易新闻实现双导航tab切换

    一.问题描述 双导航tab切换(底部区块+区域内头部导航),实现方案底部区域使用FragmentTabHost+Fragment, 区域内头部导航使用ViewPager+Fragment,可在之前博客 ...

最新文章

  1. iot架构 mqtt netty_Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上
  2. 每日一皮:项目开发停在了最后10%的效果...
  3. 程序员需要牢记的一点
  4. visual studio 2019配置OnnxRuntime+推理+vgg16
  5. 一文弄懂各大池化Pooling操作
  6. linux多线程编程——同步与互斥
  7. 国贸专业要考计算机二级,国贸专业考计算机二级有没有必要
  8. springboot开启debug日志_SpringBoot 如何优雅的打印日志?
  9. C++ 中 freopen()函数的用法
  10. CocoaPods管理iOS项目 2018年11月06日
  11. MATLAB破解版解决帮助文档需要许可证的问题
  12. word文档压缩图片
  13. 针对不同的客户采取不同的沟通方式
  14. 工业软件开发-odoo
  15. 数据结构与算法一:稀疏数组 队列 链表
  16. 我心爱的吉他坏了,心里像少了什么一样:(
  17. (15)卡巴斯基防病毒软件介绍-概述
  18. 【黑客故事】程序员作家王小波
  19. Python进阶并发基础--线程,全局解释器锁GIL由来,如何更好的利用Python线程,
  20. 阿里云服务器DDoS防御方法免受攻击的详细内容

热门文章

  1. python 爬取 全网代理 IP 网站 + 破解端口加密混淆
  2. 第2章-计算机组成原理之概述篇
  3. phpeclipse
  4. php eclipse 插件安装,phpeclipse插件下载-phpeclipse插件官方版 v1.2.3 官方最新版 - 安下载...
  5. 博弈论笔记:动态博弈
  6. 写论文、搞科研、读大学必备的28款软件。
  7. 贵州学业水平测试信息技术软件,贵州信息技术学业水平考试系统操作手册.doc...
  8. 孙玄:转转如何打造AI工程架构体系
  9. 关于身份证号两个格式转换的问题
  10. 整理好全球半导体公司,看看哪些你的上下游厂家