一、前言
新闻客户端相信大家都用过,很多开发者对于新闻客户端的主界面很感兴趣,想自己开发一个。
二、源码
主要是使用了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
精彩科技工作室
相关推荐
根据提供的文档内容,我们可以归纳并深入探讨Android新闻...通过以上分析可以看出,该项目是一个完整的Android新闻客户端开发案例,涵盖了从需求分析到最终实现的全过程,对于学习Android应用开发具有较高的参考价值。
1、开发环境:Android Studio 1.4 运行环境:Android 5.0 测试机型:魅族MX3 2、使用第三方框架:slidingmenu、ViewPagerIndicator、XUtils3、极光推送、社会化分享等 3、服务端:使用Tomcat8,JSON数据是从网络...
【CSDN客户端 Android新闻客户端 完整代码】是一个针对Android平台开发的新闻阅读应用的源码项目。这个项目主要用于展示如何构建一个功能完善的新闻客户端,让用户能够在移动设备上浏览CSDN(中国软件开发者网络)上...
【Android 新闻客户端开发】 Android新闻客户端是一种移动应用,它允许用户在智能手机上浏览和阅读来自各种来源的新闻。这种应用程序通常集成了网络浏览器的功能,但具有更优化的用户体验和定制化服务。在这个案例...
本文主要介绍了基于Android平台的新闻客户端的设计与实现,旨在开发出一款智能手机新闻客户端应用程序。通过分析Android系统软件开发原理的技术层面,开发出能为用户提供更人性化、更方便的基于Android手机新闻...
通过这个新闻客户端项目,你可以系统地学习并实践Android开发的各个方面,从而提高自己的编程技能和理解能力。在实际操作中,遇到问题不要害怕,多查阅文档、参考示例,持续迭代和优化你的代码,你将逐渐成为一个...
【Android版新闻客户端】是一款基于...以上是构建Android新闻客户端的主要技术点,开发者需要熟练掌握这些技能,才能构建出稳定、高效且用户体验良好的新闻阅读应用。请记住,这个项目仅供学习参考,不应用于商业目的。
《Android新闻客户端开发详解——基于MVP、RxJava、Retrofit与OkHttp3》 在移动应用开发领域,Android新闻客户端是一种常见的应用类型,它能够实时推送新闻资讯,提供便捷的阅读体验。本文将深入探讨如何利用现代...
以上就是构建一个Android新闻客户端应用所涉及的主要技术点,涵盖了网络通信、数据解析、UI设计、本地存储等多个方面。理解并掌握这些知识点,将使你有能力创建出功能完备、用户体验优秀的新闻客户端应用。
1. **基础架构搭建**:开发一个Android新闻客户端,首先需要建立一个用户友好的界面,通常包括标题列表、文章详情页、搜索功能等。这涉及到Android的布局管理器(如LinearLayout, RecyclerView)以及数据绑定技术...
以上是Android新闻客户端代码的主要知识点,涵盖UI设计、数据获取与存储、用户交互、性能优化等多个方面,体现了Android应用开发的综合能力。通过这样的项目实践,开发者能够深入理解Android系统的工作原理,并提升...
帮助android开发者更好的学习,使得android初学者能够获得更多的技术,虽然只是一个简单的项目。
在Android开发领域,构建一个新闻客户端是常见的应用场景,它涵盖了用户交互、网络通信以及界面设计等多个方面。本项目"android开发新闻客户端(包含登录和注册)"提供了完整的源码,帮助开发者了解如何实现一个功能...