最近好久没有更新我的博客了,之前5月份由于在一家苦逼的初创公司,一直有时间更新blog,上周离职了,好好休息了两天,上周面了一家公司感觉挺好的,这两天一边找工作一边写写博客吧。祝我顺利等到offer吧^_^(不过北京这一段时间的Android行情不是特别好啊)
好了,开始今天的主题,在找工作用的是Boss直聘,感觉APP里面的消息界面还不错,就试着自己写了一个。以后有时间把其他界面也写一下,先看一下GIF效果。
接下来简单说一下吧!
先来看一下main布局文件吧,比较简单,先看一下图片
直接看代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cxy.boss.ui.MainActivity">
<RadioGroup
android:id="@+id/main_rg"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:weightSum="4" >
<RadioButton
android:id="@+id/rb_find_nor"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1"
android:button="@null"
android:checked="true"
android:drawableTop="@drawable/rb_find_nor_selecter"
android:text="职位"
android:textSize="12sp"
android:gravity="center"/>
<RadioButton
android:id="@+id/rb_company"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@drawable/rb_company_selecter"
android:text="公司"
android:textSize="12sp"
android:gravity="center"/>
<RadioButton
android:id="@+id/rb_message"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@drawable/rb_message_selecter"
android:text="消息"
android:textSize="12sp"
android:gravity="center"/>
<RadioButton
android:id="@+id/rb_myPage"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@drawable/rb_my_selecter"
android:text="我的"
android:textSize="12sp"
android:gravity="center"/>
</RadioGroup>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#cacaca"
android:id="@+id/line"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp"
/>
<FrameLayout
android:id="@+id/id_ll_top"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
</FrameLayout>
</RelativeLayout>
底部导航是一个RadioGroup ,里面有四个RadioButton,根据radioButton 的状态来动态切换四个Fragment达到切换页面的效果。在布局文件里的RadioButton的背景是
‘’android:drawableTop="@drawable/rb_message_selecter"
我们再来看一下rb_message_selecter.xml这个文件。
drawable包下,有四个rb开头的文件,我们来看一下rb_message_selecter文件,一共三行主要代码,第一行是item被选中的时候要显示的图片资源,第二行是未被选中时显示的图片资源,第三行显示的是默认显示的图片资源。
接下来看一下MainActivity文件
MainActivity.java
package com.cxy.boss.ui;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.KeyEvent;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.cxy.boss.R;
import com.cxy.boss.fragment.Company_Fragment;
import com.cxy.boss.fragment.Find_Fragment;
import com.cxy.boss.fragment.Message_Fragment;
import com.cxy.boss.fragment.My_Fragment;
public class MainActivity extends FragmentActivity implements RadioGroup.OnCheckedChangeListener {
static long exittime = 0; //计算两次Back键按下的时间
private RadioGroup group;
private FragmentManager manager; //Fragmnet的管理器
private FragmentTransaction transaction; //Fragment事物
private My_Fragment my_fragment; //我的页面
private Find_Fragment find_fragment; //职位页面
private Company_Fragment company_fragment; //公司页面
private Message_Fragment message_fragment; //消息页面
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
/**
* @程序功能:布局初始化
* @autho:cxy
* */
private void initView() {
// findById
group = (RadioGroup) findViewById(R.id.main_rg);
manager = getSupportFragmentManager();
transaction = manager.beginTransaction();
//对RadioGroup设置监听
group.setOnCheckedChangeListener(this);
//职位的Fragmnet
find_fragment = new Find_Fragment();
//公司的Fragmnet
company_fragment = new Company_Fragment();
//消息的Fragmnet
message_fragment = new Message_Fragment();
//我的Fragment
my_fragment = new My_Fragment();
//为事物添加布局页面
transaction.add(R.id.id_ll_top,find_fragment);
transaction.add(R.id.id_ll_top,company_fragment);
transaction.add(R.id.id_ll_top,message_fragment);
transaction.add(R.id.id_ll_top,my_fragment);
// 隐藏收藏和我的界面
transaction.hide(company_fragment);
transaction.hide(my_fragment);
transaction.hide(message_fragment);
// 提交事物
transaction.commit();
//为group设置监听
group.setOnCheckedChangeListener(this);
}
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
//根据RaidoButton切换对应的页面
transaction = manager.beginTransaction();
switch (checkedId){
case R.id.rb_find_nor:
transaction.show(find_fragment);
transaction.hide(company_fragment);
transaction.hide(message_fragment);
transaction.hide(my_fragment);
break;
case R.id.rb_company:
transaction.show(company_fragment);
transaction.hide(find_fragment);
transaction.hide(message_fragment);
transaction.hide(my_fragment);
break;
case R.id.rb_message:
transaction.show(message_fragment);
transaction.hide(company_fragment);
transaction.hide(find_fragment);
transaction.hide(my_fragment);
break;
case R.id.rb_myPage:
transaction.show(my_fragment);
transaction.hide(company_fragment);
transaction.hide(message_fragment);
transaction.hide(find_fragment);
break;
default:
break;
}
//提交事务
transaction.commit();
}
//监听返回键
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK){
this.exitapp();
}
return true;
}
/**
* 程序从功能:
* 退出程序
* **/
private void exitapp() {
if ((System.currentTimeMillis() - exittime)>2000){
Toast.makeText(this,"再按一次返回键退出程序",Toast.LENGTH_SHORT).show();
exittime = System.currentTimeMillis();
}else{
System.exit(0);
}
}
}
代码里注释比较详细,在这里就不多解释了,这样就大概构成了boss直聘的最基本框架,下面来看一下Message_Fragment.java这个文件,
package com.cxy.boss.fragment;
import android.graphics.Color;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.cxy.boss.R;
import java.util.ArrayList;
import java.util.List;
/**
* 消息
* Created by cxy on 2016/11/14.
*/
public class Message_Fragment extends Fragment implements View.OnClickListener{
private ViewPager viewPager;
//顶部的聊天、互动的button
private Button btn_chat,btn_exchange;
// 聊天的Fragment
private Msg_chat_Fragment msg_chat_fragment;
//互动的Fragment
private Msg_exchange_Fragment msg_exchange_fragment;
// fragment的容器
private List<Fragment> fragments;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message,null);
initView(view);
initPager();
return view;
}
/**
* 布局初始化
* */
private void initView(View view) {
btn_chat = (Button)view. findViewById(R.id.btn_chat);
btn_exchange = (Button)view. findViewById(R.id.btn_exchange);
viewPager = (ViewPager)view. findViewById(R.id.msg_vp);
btn_chat.setOnClickListener(this);
btn_exchange.setOnClickListener(this);
}
//监听聊天和互动的点击事件
@Override
public void onClick(View view) {
switch (view.getId()){
//如果是聊天的Button点击
case R.id.btn_chat:
//设置viewPager选中第1个页面
viewPager.setCurrentItem(0);
btn_chat.setTextColor(Color.rgb(83,202,195));
btn_chat.setBackgroundColor(Color.rgb(255,255,255));
btn_exchange.setTextColor(Color.rgb(255,255,255));
btn_exchange.setBackgroundColor(Color.rgb(83,202,195));
break;
// 如果是互动的Button点击
case R.id.btn_exchange:
//设置viewPager选中第2个页面
viewPager.setCurrentItem(1);
// 设置文字颜色和button背景色
btn_exchange.setTextColor(Color.rgb(83,202,195));
btn_exchange.setBackgroundColor(Color.rgb(255,255,255));
btn_chat.setTextColor(Color.rgb(255,255,255));
btn_chat.setBackgroundColor(Color.rgb(83,202,195));
break;
}
}
/**
* 初始化ViewPager
* */
private void initPager(){
fragments = new ArrayList<Fragment>();
msg_chat_fragment = new Msg_chat_Fragment();
msg_exchange_fragment = new Msg_exchange_Fragment();
fragments.add(msg_chat_fragment);
fragments.add(msg_exchange_fragment);
//设置适配器
viewPager.setAdapter(new MyPagerAdapter(getFragmentManager()));
//设置viewPager的监听
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//根据position的值来改变顶部button的切换。文字颜色和背景颜色
if (position==0){
btn_chat.setTextColor(Color.rgb(83,202,195));
btn_chat.setBackgroundColor(Color.rgb(255,255,255));
btn_exchange.setTextColor(Color.rgb(255,255,255));
btn_exchange.setBackgroundColor(Color.rgb(83,202,195));
}else{
btn_exchange.setTextColor(Color.rgb(83,202,195));
btn_exchange.setBackgroundColor(Color.rgb(255,255,255));
btn_chat.setTextColor(Color.rgb(255,255,255));
btn_chat.setBackgroundColor(Color.rgb(83,202,195));
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
// viewPager适配器
class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
}
注释比较详细,就不做过多解释了。
再来看一下消息的Fragment文件
package com.cxy.boss.fragment;
import android.graphics.Color;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.cxy.boss.R;
import java.util.ArrayList;
import java.util.List;
/**
* 互动页面
* Created by cxy on 2016/11/14.
*/
public class Msg_exchange_Fragment extends Fragment implements View.OnClickListener{
//申明ViewPager
private ViewPager vp;
//申明相关组件
private TextView tv_likeMe;
private TextView tv_seeMe;
private TextView tv_newJob;
private List<Fragment> fragments;
//对我有意,谁看过我,新职位的Fragment
private Exc_Likeme_Fragment likeMeFragment;
private Exc_Seeme_Fragment seeMeFragment;
private Exc_newJob_Fragment newJobFragment;
// 定义必要变量和组件
// 看到width这个变量, 是用来控制绿色线条的宽度,与Display、LayoutParams 配合使用。
private int width;
private Display mDisplay;
private LinearLayout.LayoutParams params;
private View mViewLine;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_msg_exchange,null);
initView(view);
return view;
}
/**
* 布局初始化
* */
private void initView(View view) {
fragments = new ArrayList<>();
likeMeFragment = new Exc_Likeme_Fragment();
seeMeFragment = new Exc_Seeme_Fragment();
newJobFragment = new Exc_newJob_Fragment();
//像list里添加fragment
fragments.add(likeMeFragment);
fragments.add(seeMeFragment);
fragments.add(newJobFragment);
// findID
vp = (ViewPager) view.findViewById(R.id.exce_vp);
mViewLine = (View)view.findViewById(R.id.tab_line);
tv_likeMe = (TextView) view.findViewById(R.id.tv_likeMe);
tv_seeMe = (TextView) view.findViewById(R.id.tv_seeMe);
tv_newJob = (TextView) view.findViewById(R.id.tv_newJob);
//设置监听
tv_likeMe.setOnClickListener(this);
tv_seeMe.setOnClickListener(this);
tv_newJob.setOnClickListener(this);
//设置适配器
vp.setAdapter(new MyPagerAdapter(getFragmentManager()));
// 获取当前窗口的display
mDisplay = getActivity().getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
mDisplay.getMetrics(outMetrics);
width = outMetrics.widthPixels/3;
params = (LinearLayout.LayoutParams)mViewLine.getLayoutParams();
params.width = width;
mViewLine.setLayoutParams(params);
vp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(positionOffset != 0 && positionOffsetPixels != 0 ){
params.leftMargin = positionOffsetPixels / fragments.size() + width * position ;
mViewLine.setLayoutParams(params);
}
}
// 根据选择的状态给便能字体颜色
@Override
public void onPageSelected(int position) {
switch (position){
case 0:
tv_likeMe.setTextColor(Color.rgb(153,153,153));
tv_seeMe.setTextColor(Color.rgb(187,187,187));
tv_newJob.setTextColor(Color.rgb(187,187,187));
break;
case 1:
tv_seeMe.setTextColor(Color.rgb(153,153,153));
tv_likeMe.setTextColor(Color.rgb(187,187,187));
tv_newJob.setTextColor(Color.rgb(187,187,187));
break;
case 2:
tv_newJob.setTextColor(Color.rgb(153,153,153));
tv_seeMe.setTextColor(Color.rgb(187,187,187));
tv_likeMe.setTextColor(Color.rgb(187,187,187));
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
/**
* 对顶部的Tab的TextView设置监听来改变选中
* 的字体颜色和设置ViewPager到与点击项相匹配的position
*/
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.tv_likeMe:
vp.setCurrentItem(0);
tv_likeMe.setTextColor(Color.rgb(153,153,153));
tv_seeMe.setTextColor(Color.rgb(187,187,187));
tv_newJob.setTextColor(Color.rgb(187,187,187));
break;
case R.id.tv_seeMe:
vp.setCurrentItem(1);
tv_seeMe.setTextColor(Color.rgb(153,153,153));
tv_likeMe.setTextColor(Color.rgb(187,187,187));
tv_newJob.setTextColor(Color.rgb(187,187,187));
break;
case R.id.tv_newJob:
vp.setCurrentItem(2);
tv_newJob.setTextColor(Color.rgb(153,153,153));
tv_seeMe.setTextColor(Color.rgb(187,187,187));
tv_likeMe.setTextColor(Color.rgb(187,187,187));
break;
}
}
// 适配器
class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
}
相关解释都写在代码里了,现在来分析一下。
看到width这个变量, 是用来控制红色线条的宽度,与Display、LayoutParams 配合使用。
pageCount主要是用来计算当前滑动的时候, 线条的左右边距。
解题思路: 主要操作其实就是那条红色的提示线。 当我们在滚动ViewPager的 时候, 只需要能够动态的操作提示线的左边距属性MarginLeft即可。
所以我们需要对ViewPager提供滚动的监听器, 其主要操作的方法就是public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
理解属性:
position,当前选中的页面位置(从0开始);
positionOffset, 大小从0到屏幕宽度或从屏幕宽度到0。 取决于你的左右滑动状态。
positionOffsetPixels,
主要就是对我们手指状态的一个操作。 值为1的时候, 正在滑动、 2: 手指抬起, 0: 结束了。
开始进入算法逻辑:
在我们的onPageScrolled中的处理,
首先我们需要保证当前的ViewPager处于可滑动状态。 否则就不要进行逻辑处理了,不然消费太大。
然后我们已经提前获取到了提示线的LayoutParams对象(不要在该方法啊中获取LayoutParams,
不然非常浪费内存) 。
params.leftMargin
= positionOffsetPixels / pageCount + width * position ; 可以看出我们一直在不停的给MarginLeft计算值
然后mViewLine.stLayoutParams(params);不停的进行绘制,
这样可以有一种类似于动画的效果体现。
计算:
positionOffsetPixels / pageCount: 我们有三个页面, 这样计算可以正常的分配每个Tab占有的屏幕宽度值;width * position : width为提示线宽度, 这个值基本上就不需改变了。 position前面解释过意思了。 这样可以计算出我的当前MarginLeft的所需宽度大小。 (之后一直setLayoutParams就可以了。)
基本的逻辑都是比较清晰的, 也非常的容易懂。 (不喜请喷!!!)
最后放上demo的地址:
http://download.csdn.net/detail/xiaoyu940601/9868389