一、前言
新闻客户端相信大家都用过,很多开发者对于新闻客户端的主界面很感兴趣,想自己开发一个。
二、源码
主要是使用了SlidingMenu这样一个自定义控件,实现左边和右边都能滑动出菜单界面,而主界面是使用的viewFlipper控件。滑动的菜单和主界面都为fragment
1、SlidingMenu控件代码:
public class SlidingMenu extends RelativeLayout {
private View mSlidingView;
// private View mMenuView;// 左边菜单view
private View mDetailView;// 右边消息view
private RelativeLayout bgShade;
private int screenWidth;
private int screenHeight;
private Context mContext;
private Scroller mScroller;
private VelocityTracker mVelocityTracker;
private int mTouchSlop;
private float mLastMotionX;
private float mLastMotionY;
private static final int VELOCITY = 50;
private boolean mIsBeingDragged = true;
private boolean tCanSlideLeft = true;
private boolean tCanSlideRight = false;
private boolean hasClickLeft = false;
private boolean hasClickRight = false;
public SlidingMenu(Context context) {
super(context);
init(context);
}
private void init(Context context) {
mContext = context;
bgShade = new RelativeLayout(context);
mScroller = new Scroller(getContext());
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
WindowManager windowManager = ((Activity) context).getWindow().getWindowManager();
Display display = windowManager.getDefaultDisplay();
screenWidth = display.getWidth();
screenHeight = display.getHeight();
LayoutParams bgParams = new LayoutParams(screenWidth, screenHeight);
bgParams.addRule(RelativeLayout.CENTER_IN_PARENT);
bgShade.setLayoutParams(bgParams);
}
public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
// 暂时无用
public void addViews(View left, View center, View right) {
// setLeftView(left);
setRightView(right);
setCenterView(center);
}
// 设置左边view
// public void setLeftView(View view) {
// LayoutParams behindParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
// LayoutParams.MATCH_PARENT);
// addView(view, behindParams);
// mMenuView = view;
// }
//
// public View getLeftView() {
// return mMenuView;
// }
public View getRightView() {
return mDetailView;
}
// 设置右边view
public void setRightView(View view) {
LayoutParams behindParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
behindParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
addView(view, behindParams);
mDetailView = view;
}
// 设置中间view
public void setCenterView(View view) {
LayoutParams aboveParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
LayoutParams bgParams = new LayoutParams(screenWidth, screenHeight);
bgParams.addRule(RelativeLayout.CENTER_IN_PARENT);
View bgShadeContent = new View(mContext);
bgShadeContent.setBackgroundResource(R.drawable.shade_bg);
bgShade.addView(bgShadeContent, bgParams);
addView(bgShade, bgParams);
addView(view, aboveParams);
mSlidingView = view;
mSlidingView.bringToFront();
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
postInvalidate();
}
@Override
public void computeScroll() {
if (!mScroller.isFinished()) {
if (mScroller.computeScrollOffset()) {
int oldX = mSlidingView.getScrollX();
int oldY = mSlidingView.getScrollY();
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
if (mSlidingView != null) {
mSlidingView.scrollTo(x, y);
if (x < 0)
bgShade.scrollTo(x + 10, y);// 背景阴影右偏
else
bgShade.scrollTo(x - 10, y);// 背景阴影左偏
}
}
invalidate();
}
}
}
private boolean canSlideLeft = true;// 是否能向左滑动
private boolean canSlideRight = false;// 是否能向右滑动
public void setCanSliding(boolean left, boolean right) {
canSlideLeft = left;
canSlideRight = right;
}
/* 拦截touch事件 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final float x = ev.getX();
final float y = ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
// showToast("MotionEvent.ACTION_DOWN....");
mLastMotionX = x;
mLastMotionY = y;
mIsBeingDragged = false;
if (canSlideLeft) {
// mMenuView.setVisibility(View.VISIBLE);
mDetailView.setVisibility(View.INVISIBLE);
}
if (canSlideRight) {
// mMenuView.setVisibility(View.INVISIBLE);
mDetailView.setVisibility(View.VISIBLE);
}
break;
case MotionEvent.ACTION_MOVE:
// showToast("MotionEvent.ACTION_MOVE....");
final float dx = x - mLastMotionX;
final float xDiff = Math.abs(dx);
final float yDiff = Math.abs(y - mLastMotionY);
if (xDiff > mTouchSlop && xDiff > yDiff) {
if (canSlideLeft) {
float oldScrollX = mSlidingView.getScrollX();
if (oldScrollX < 0) {
mIsBeingDragged = true;
mLastMotionX = x;
} else {
if (dx > 0) {
mIsBeingDragged = true;
mLastMotionX = x;
}
}
} else if (canSlideRight) {
float oldScrollX = mSlidingView.getScrollX();
if (oldScrollX > 0) {
mIsBeingDragged = true;
mLastMotionX = x;
} else {
if (dx < 0) {
mIsBeingDragged = true;
mLastMotionX = x;
}
}
}
}
break;
}
return mIsBeingDragged;
}
/* 处理拦截后的touch事件 */
@SuppressLint("Recycle")
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
final int action = ev.getAction();
final float x = ev.getX();
final float y = ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionX = x;
mLastMotionY = y;
if (mSlidingView.getScrollX() == -getMenuViewWidth()
&& mLastMotionX < getMenuViewWidth()) {
return false;
}
if (mSlidingView.getScrollX() == getDetailViewWidth()
&& mLastMotionX > getMenuViewWidth()) {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
if (mIsBeingDragged) {
final float deltaX = mLastMotionX - x;
mLastMotionX = x;
float oldScrollX = mSlidingView.getScrollX();
float scrollX = oldScrollX + deltaX;
if (canSlideLeft) {
if (scrollX > 0)
scrollX = 0;
}
if (canSlideRight) {
if (scrollX < 0)
scrollX = 0;
}
if (deltaX < 0 && oldScrollX < 0) { // left view
final float leftBound = 0;
final float rightBound = -getMenuViewWidth();
if (scrollX > leftBound) {
scrollX = leftBound;
} else if (scrollX < rightBound) {
scrollX = rightBound;
}
} else if (deltaX > 0 && oldScrollX > 0) { // right view
final float rightBound = getDetailViewWidth();
final float leftBound = 0;
if (scrollX < leftBound) {
scrollX = leftBound;
} else if (scrollX > rightBound) {
scrollX = rightBound;
}
}
if (mSlidingView != null) {
mSlidingView.scrollTo((int) scrollX, mSlidingView.getScrollY());
if (scrollX < 0) {// Left View
bgShade.scrollTo((int) scrollX + 10, mSlidingView.getScrollY());
} else {// Right View
bgShade.scrollTo((int) scrollX - 10, mSlidingView.getScrollY());
}
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(100);
float xVelocity = velocityTracker.getXVelocity();// 滑动的速度
int oldScrollX = mSlidingView.getScrollX();
int dx = 0;
if (oldScrollX <= 0 && canSlideLeft) {// left view
if (xVelocity > VELOCITY) {
dx = -getMenuViewWidth() - oldScrollX;
} else if (xVelocity < -VELOCITY) {
dx = -oldScrollX;
if (hasClickLeft) {
hasClickLeft = false;
setCanSliding(tCanSlideLeft, tCanSlideRight);
}
} else if (oldScrollX < -getMenuViewWidth() / 2) {
dx = -getMenuViewWidth() - oldScrollX;
} else if (oldScrollX >= -getMenuViewWidth() / 2) {
dx = -oldScrollX;
if (hasClickLeft) {
hasClickLeft = false;
setCanSliding(tCanSlideLeft, tCanSlideRight);
}
}
}
if (oldScrollX >= 0 && canSlideRight) {
if (xVelocity < -VELOCITY) {
dx = getDetailViewWidth() - oldScrollX;
} else if (xVelocity > VELOCITY) {
dx = -oldScrollX;
if (hasClickRight) {
hasClickRight = false;
setCanSliding(tCanSlideLeft, tCanSlideRight);
}
} else if (oldScrollX > getDetailViewWidth() / 2) {
dx = getDetailViewWidth() - oldScrollX;
} else if (oldScrollX <= getDetailViewWidth() / 2) {
dx = -oldScrollX;
if (hasClickRight) {
hasClickRight = false;
setCanSliding(tCanSlideLeft, tCanSlideRight);
}
}
}
smoothScrollTo(dx);
}
break;
}
return true;
}
public int getMenuViewWidth() {
// if (mMenuView == null) {
return 0;
// }
// return mMenuView.getWidth();
}
public int getDetailViewWidth() {
if (mDetailView == null) {
return 0;
}
return mDetailView.getWidth();
}
void smoothScrollTo(int dx) {
int duration = 500;
int oldScrollX = mSlidingView.getScrollX();
mScroller.startScroll(oldScrollX, mSlidingView.getScrollY(), dx, mSlidingView.getScrollY(),
duration);
if (oldScrollX < 0) {// Left
if (dx <= 0) {// Left 显示
showLeft = true;
} else {
showLeft = false;
}
} else {// Right
if (dx >= 0) {// Right 显示
showRight = true;
} else {
showRight = false;
}
}
invalidate();
}
public boolean showLeft = false;
/*
* 显示左侧边的view
*/
// public void showLeftView() {
// // int menuWidth = mMenuView.getWidth();
// int oldScrollX = mSlidingView.getScrollX();
// if (oldScrollX == 0) {
// mMenuView.setVisibility(View.VISIBLE);
// mDetailView.setVisibility(View.INVISIBLE);
// smoothScrollTo(-menuWidth);
// tCanSlideLeft = canSlideLeft;
// tCanSlideRight = canSlideRight;
// hasClickLeft = true;
// setCanSliding(true, false);
// showLeft = true;
// } else if (oldScrollX == -menuWidth) {
// smoothScrollTo(menuWidth);
// showLeft = false;
// if (hasClickLeft) {
// hasClickLeft = false;
// setCanSliding(tCanSlideLeft, tCanSlideRight);
// }
// }
// }
public boolean showRight = false;
/* 显示右侧边的view */
public void showRightView() {
int menuWidth = mDetailView.getWidth();
int oldScrollX = mSlidingView.getScrollX();
if (oldScrollX == 0) {
// mMenuView.setVisibility(View.INVISIBLE);
mDetailView.setVisibility(View.VISIBLE);
smoothScrollTo(menuWidth);
tCanSlideLeft = canSlideLeft;
tCanSlideRight = canSlideRight;
hasClickRight = true;
showRight = true;
showLeft = false;
setCanSliding(false, true);
} else if (oldScrollX == menuWidth) {
smoothScrollTo(-menuWidth);
showRight = false;
if (hasClickRight) {
hasClickRight = false;
setCanSliding(tCanSlideLeft, tCanSlideRight);
}
}
}
public boolean getLeftVisbility() {
return showLeft;
}
public boolean getRightVisbility() {
return showRight;
}
}
说明:因为我这个客户端只能右边显示出菜单,所以对代码进行了修改,如上注释部分的代码。
2、布局文件
2.1 mainActivity布局
<SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/slidingMenu" android:layout_width="match_parent" android:layout_height="match_parent" />
2.2 右边菜单和主界面布局是一样的
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/right_frame" android:layout_width="fill_parent" android:layout_height="fill_parent" />
2.3 mainFragment布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <include layout="@layout/title"/> <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="5dip" android:paddingTop="10dip" android:background="@color/lightgrey" android:orientation="horizontal" > <TextView android:id="@+id/tab_history" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1.0" android:gravity="center" android:text="@string/tab1" android:textColor="@color/white" android:textSize="15sp"/> <TextView android:id="@+id/tab_knowlodge" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1.0" android:gravity="center" android:text="@string/tab2" android:textColor="@color/blue" android:textSize="15sp"/> <TextView android:id="@+id/tab_joker" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1.0" android:gravity="center" android:text="@string/tab3" android:textColor="@color/blue" android:textSize="15sp"/> <!-- <TextView --> <!-- android:id="@+id/tab_star" --> <!-- android:layout_width="match_parent" --> <!-- android:layout_height="match_parent" --> <!-- android:layout_weight="1.0" --> <!-- android:gravity="center" --> <!-- android:text="@string/tab_4" --> <!-- android:textColor="@color/blue" --> <!-- android:textSize="15sp"/> --> </LinearLayout> <!-- <LinearLayout --> <!-- android:layout_width="match_parent" --> <!-- android:layout_height="wrap_content" --> <!-- android:layout_gravity="bottom" --> <!-- android:orientation="vertical" --> <!-- android:paddingBottom="3dip"> --> <ImageView android:id="@+id/iv_bottom_line" android:layout_width="40dip" android:layout_height="2dip" android:layout_marginLeft="40dip" android:scaleType="matrix" android:contentDescription="@null" android:src="#fff"> </ImageView> <!-- </LinearLayout> --> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" /> </LinearLayout>
3、mainFragment源码
public class MainFragment extends Fragment implements ViewPager.OnPageChangeListener,
OnClickListener {
private ViewPager viewPager;
private List<Fragment> fragments;
private TextView historyText, jokerText, knowledgeText;
private ImageView lineImage;
private ImageButton mUserBtn, mCommentBtn;
private int currIndex = 0;
private float position_one, position_two;
private OnShowLeftListener mListener;
public interface OnShowLeftListener {
public void showLeftFragment();
}
public static MainFragment instance() {
return new MainFragment();
}
@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_main, container, false);
init(view);
return view;
}
private void init(View view) {
viewPager = (ViewPager) view.findViewById(R.id.viewPager);
fragments = new ArrayList<Fragment>();
fragments.add(NewsFragment.instance());// 添加客户端主界面所有的fragment
fragments.add(InfoFragment.instance());
fragments.add(StategyFragment.instance());
ViewAdapter adapter = new ViewAdapter(getFragmentManager(), fragments);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(0);
viewPager.setOnPageChangeListener(this);
historyText = (TextView) view.findViewById(R.id.tab_history);
jokerText = (TextView) view.findViewById(R.id.tab_joker);
knowledgeText = (TextView) view.findViewById(R.id.tab_knowlodge);
historyText.setOnClickListener(this);
jokerText.setOnClickListener(this);
knowledgeText.setOnClickListener(this);
lineImage = (ImageView) view.findViewById(R.id.iv_bottom_line);
// int bottomLineWidth = lineImage.getLayoutParams().width;
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenW = dm.widthPixels;
position_one = (float) screenW / (fragments.size());
position_two = position_one * 2;
// position_three = position_one * 3;
mUserBtn = (ImageButton) view.findViewById(R.id.button_user);
mUserBtn.setOnClickListener(this);
mCommentBtn = (ImageButton) view.findViewById(R.id.button_comment);
mCommentBtn.setOnClickListener(this);
mCommentBtn.setVisibility(View.GONE);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tab_history:
viewPager.setCurrentItem(0);
break;
case R.id.tab_joker:
viewPager.setCurrentItem(2);
break;
// case R.id.tab_star:
// if (checkUser())
// viewPager.setCurrentItem(3);
// break;
case R.id.tab_knowlodge:
viewPager.setCurrentItem(1);
break;
case R.id.button_user:
mListener.showLeftFragment();
break;
case R.id.button_comment:
// appwall.doShowAppWall();
break;
default:
viewPager.setCurrentItem(0);
break;
}
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int arg0) {
Animation animation = null;
switch (arg0) {
case 0:
if (currIndex == 1) {
animation = new TranslateAnimation(position_one, 0, 0, 0);
knowledgeText.setTextColor(getResources().getColor(R.color.blue));
} else if (currIndex == 2) {
animation = new TranslateAnimation(position_two, 0, 0, 0);
jokerText.setTextColor(getResources().getColor(R.color.blue));
}
// else if (currIndex == 3) {
// animation = new TranslateAnimation(position_three, 0, 0, 0);
// starText.setTextColor(getResources().getColor(R.color.blue));
// }
historyText.setTextColor(getResources().getColor(R.color.white));
break;
case 1:
if (currIndex == 0) {
animation = new TranslateAnimation(0, position_one, 0, 0);
historyText.setTextColor(getResources().getColor(R.color.blue));
} else if (currIndex == 2) {
animation = new TranslateAnimation(position_two, position_one, 0, 0);
jokerText.setTextColor(getResources().getColor(R.color.blue));
}
// else if (currIndex == 3) {
// animation = new TranslateAnimation(position_three, position_one, 0, 0);
// starText.setTextColor(getResources().getColor(R.color.blue));
// }
knowledgeText.setTextColor(getResources().getColor(R.color.white));
break;
case 2:
if (currIndex == 0) {
animation = new TranslateAnimation(0, position_two, 0, 0);
historyText.setTextColor(getResources().getColor(R.color.blue));
} else if (currIndex == 1) {
animation = new TranslateAnimation(position_one, position_two, 0, 0);
knowledgeText.setTextColor(getResources().getColor(R.color.blue));
}
// else if (currIndex == 3) {
// animation = new TranslateAnimation(position_three, position_two, 0, 0);
// starText.setTextColor(getResources().getColor(R.color.blue));
// }
jokerText.setTextColor(getResources().getColor(R.color.white));
break;
// case 3:
// if (checkUser()) {
// if (currIndex == 0) {
// animation = new TranslateAnimation(0, position_three, 0, 0);
// historyText.setTextColor(getResources().getColor(R.color.blue));
// } else if (currIndex == 1) {
// animation = new TranslateAnimation(position_one, position_three, 0, 0);
// knowledgeText.setTextColor(getResources().getColor(R.color.blue));
// } else if (currIndex == 2) {
// animation = new TranslateAnimation(position_two, position_three, 0, 0);
// jokerText.setTextColor(getResources().getColor(R.color.blue));
// }
// starText.setTextColor(getResources().getColor(R.color.white));
// }
// break;
}
if (animation != null) {
currIndex = arg0;
animation.setFillAfter(true);
animation.setDuration(300);
lineImage.startAnimation(animation);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mListener = (OnShowLeftListener) activity;
}
}
4、mainActivity源码
public class MainActivity extends FragmentActivity implements MainFragment.OnShowLeftListener {
private SlidingMenu mSlidingMenu;
private MainFragment mMainFrag;
private UserFragment mUserFrag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSlidingMenu = (SlidingMenu) findViewById(R.id.slidingMenu);
mSlidingMenu.setRightView(getLayoutInflater().inflate(R.layout.right_frame, null));
mSlidingMenu.setCenterView(getLayoutInflater().inflate(R.layout.center_frame, null));
FragmentTransaction t = this.getSupportFragmentManager().beginTransaction();
mMainFrag = MainFragment.instance();
t.replace(R.id.center_frame, mMainFrag);
mUserFrag = UserFragment.instance();
t.replace(R.id.right_frame, mUserFrag);
t.commit();
mSlidingMenu.setCanSliding(false, true);
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
public void showLeftFragment() {
mSlidingMenu.showRightView();
}
}
三、总结
以上基本上就是一个客户端的主界面开发,欢迎大家去下载我自己开发的一个新闻客户端,谢谢大家!
http://android.myapp.com/myapp/detail.htm?apkName=com.yln.history
精彩科技工作室