編輯:關於Android編程
國際慣例,先來效果圖
在閱讀本文章之前,請確定熟悉【Scroller】相關的知識,如果不熟悉,請小伙伴兒先百度後再來吧。
假如你已經知道【Scroller】了,那麼就接著往下看吧。
首先,我們把側拉菜單的構造給解析出來。多次觀看上面的效果圖,我們可以得出以下的結論。
整體可以看做是一個ViewGroup,這個ViewGroup包含了最多三個子View(分別是左菜單的紅色View、中間正文內容的白色View、右菜單的藍色View);三個子View(我稱為UI界面,因為代碼中的Java類就取名這個)的移動是在ViewGroup的onTouchEvent方法中控制;每個UI界面都擁有獨特的東西,比如子控件布局,因此我們希望用R.layout.*的方式引入;每個UI界面又都擁有相同的屬性,比如都有寬度屬性,滑動臨界值屬性,那麼就可以用一個超類來封裝所有相似的東西;最最重要的地方,動態計算出scrollX的值,然後用Scroller來滑動。 理清楚了結構後,我們來開始第一步的設計,也就是封裝超類,首先給出代碼:
/** * Created by ccwxf on 2016/6/14. */ public abstract class UI { protected Context context; //當前UI界面的布局文件 protected View contentView; //當前UI界面在父控件的起點X坐標 protected int startX; //當前UI界面在父控件的終點X坐標 protected int stopX; //當前UI界面的寬度 protected int width; protected UI(Context context, View contentView){ this.context = context; this.contentView = contentView; } protected abstract void calculate(float leftScale, float rightScale); protected void show(Scroller mScroller){ if(mScroller != null){ mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), startX - mScroller.getFinalX(), 0); } } }這個UI超類就用於模擬每一個界面,其中主要封裝了內容View的設置、跳轉界面的邏輯代碼,以及暴露出去需要子類實現的calculate方法,這個calculate方法主要是要計算startX、stopX、width以及各子類獨有的屬性。
/** * Created by ccwxf on 2016/6/14. */ public class LeftMenuUI extends UI { // 是指要打開該UI界面所需要滾動的X坐標臨界值 public int openX; // 是指要關閉該UI界面所需要的滾動的X坐標臨界值 public int closeX; public LeftMenuUI(Context context, View contentView) { super(context, contentView); } @Override protected void calculate(float leftScale, float rightScale) { startX = 0; stopX = (int) (Util.getScreenWidth(context) * leftScale); this.width = stopX - startX; this.openX = (int) (startX + (1 - SideLayout.DEFAULT_SIDE) * this.width); this.closeX = (int) (startX + SideLayout.DEFAULT_SIDE * this.width); } }
public class ContentUI extends UI { public ContentUI(Context context, View contentView) { super(context, contentView); } @Override protected void calculate(float leftScale, float rightScale) { int width = Util.getScreenWidth(context); int leftWidth = (int) (width * leftScale); startX = leftWidth; stopX = leftWidth + width; this.width = stopX - startX; } }
/** * Created by ccwxf on 2016/6/14. */ public class RightMenuUI extends UI { // 是指要打開該UI界面所需要滾動的X坐標臨界值 public int openX; // 是指要關閉該UI界面所需要的滾動的X坐標臨界值 public int closeX; public RightMenuUI(Context context, View contentView) { super(context, contentView); } @Override protected void calculate(float leftScale, float rightScale) { int width = Util.getScreenWidth(context); startX = (int) (width * (1 + leftScale)); stopX = (int) (width * (1 + leftScale + rightScale)); this.width = stopX - startX; this.openX = (int) (startX - width + SideLayout.DEFAULT_SIDE * this.width); this.closeX = (int) (startX - width + (1 - SideLayout.DEFAULT_SIDE) * this.width); } /** * 必須重載父類方法,因為滑動的起點是從0開始 */ protected void show(Scroller mScroller, int measureWidth){ if(mScroller != null){ mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), measureWidth - Util.getScreenWidth(context) - mScroller.getFinalX(), 0); } } }
/** * Created by ccwxf on 2016/6/14. */ public class SideLayout extends LinearLayout { //默認的菜單寬度與屏幕寬度的比值 public static final float DEFAULT_SCALE = 0.66f; //默認的滑動切換閥值相對於菜單寬度的比值 public static final float DEFAULT_SIDE = 0.25f; private Scroller mScroller; //三個UI界面 private LeftMenuUI leftMenuUI; private ContentUI contentUI; private RightMenuUI rightMenuUI; //左菜單和右菜單相對於屏幕的比值 private float leftScale = 0; private float rightScale = 0; //控件的測量寬度 private float measureWidth = 0; //手指Touch時的X坐標和移動時的X坐標 private float mTouchX; private float mMoveX; public SideLayout(Context context) { super(context); init(); } public SideLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SideLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mScroller = new Scroller(getContext()); setOrientation(LinearLayout.HORIZONTAL); } /** * 設置左菜單的布局 * @param view 左菜單布局 * @return 返回當類 */ public SideLayout setLeftMenuView(View view){ return setLeftMenuView(view, DEFAULT_SCALE); } public SideLayout setLeftMenuView(View view, float leftScale){ leftMenuUI = new LeftMenuUI(getContext(), view); this.leftScale = leftScale; return this; } /** * 設置右菜單的布局 * @param view 右菜單布局 * @return 當類 */ public SideLayout setRightMenuView(View view){ return setRightMenuView(view, DEFAULT_SCALE); } public SideLayout setRightMenuView(View view, float rightScale){ rightMenuUI = new RightMenuUI(getContext(), view); this.rightScale = rightScale; return this; } /** * 設置正文布局 * @param view 正文布局 * @return 返回當類 */ public SideLayout setContentView(View view){ contentUI = new ContentUI(getContext(), view); return this; } /** * 提交配置,必須調用 */ public void commit() { removeAllViews(); if(leftMenuUI != null){ leftMenuUI.calculate(leftScale, rightScale); measureWidth += leftMenuUI.width; addView(leftMenuUI.contentView, new LayoutParams(leftMenuUI.width, LayoutParams.MATCH_PARENT)); } if(contentUI != null){ contentUI.calculate(leftScale, rightScale); measureWidth += contentUI.width; addView(contentUI.contentView, new LayoutParams(contentUI.width, LayoutParams.MATCH_PARENT)); } if(rightMenuUI != null){ rightMenuUI.calculate(leftScale, rightScale); measureWidth += rightMenuUI.width; addView(rightMenuUI.contentView, new LayoutParams(rightMenuUI.width, LayoutParams.MATCH_PARENT)); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mTouchX = event.getX(); mMoveX = event.getX(); return true; case MotionEvent.ACTION_MOVE: int dx = (int) (event.getX() - mMoveX); if(dx > 0){ //右滑 if(mScroller.getFinalX() > 0){ mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), -dx, 0); }else{ mScroller.setFinalX(0); } }else{ //左滑 if(mScroller.getFinalX() + Util.getScreenWidth(getContext()) - dx < measureWidth){ mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), -dx, 0); }else{ mScroller.setFinalX((int) (measureWidth - Util.getScreenWidth(getContext()))); } } mMoveX = event.getX(); invalidate(); break; case MotionEvent.ACTION_UP: toTargetUI((int) (event.getX() - mTouchX)); break; } return super.onTouchEvent(event); } /** * 滑動切換到目標的UI界面 * @param dx 手指抬起時相比手指落下,滑動的距離 */ private void toTargetUI(int dx){ int scrollX = mScroller.getFinalX(); if(dx > 0){ //右滑 if(leftMenuUI != null){ if(scrollX >= leftMenuUI.openX && scrollX < leftMenuUI.stopX){ contentUI.show(mScroller); }else if(scrollX >= leftMenuUI.startX && scrollX < leftMenuUI.openX){ leftMenuUI.show(mScroller); } } if(rightMenuUI != null){ if(scrollX >= rightMenuUI.closeX){ rightMenuUI.show(mScroller, (int) measureWidth); }else if(scrollX >= contentUI.startX && scrollX < rightMenuUI.closeX){ contentUI.show(mScroller); } } }else{ //左滑 if(leftMenuUI != null){ if(scrollX > leftMenuUI.startX && scrollX <= leftMenuUI.closeX){ leftMenuUI.show(mScroller); }else if(scrollX > leftMenuUI.closeX && scrollX < leftMenuUI.stopX){ contentUI.show(mScroller); } } if(rightMenuUI != null){ if(scrollX > contentUI.startX && scrollX <= rightMenuUI.openX){ contentUI.show(mScroller); }else if(scrollX > rightMenuUI.openX){ rightMenuUI.show(mScroller, (int) measureWidth); } } } } @Override public void computeScroll(){ if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } super.computeScroll(); } }
/** * 滑動切換到目標的UI界面 * @param dx 手指抬起時相比手指落下,滑動的距離 */ private void toTargetUI(int dx){ int scrollX = mScroller.getFinalX(); if(dx > 0){ //右滑 if(leftMenuUI != null){ if(scrollX >= leftMenuUI.openX && scrollX < leftMenuUI.stopX){ contentUI.show(mScroller); }else if(scrollX >= leftMenuUI.startX && scrollX < leftMenuUI.openX){ leftMenuUI.show(mScroller); } } if(rightMenuUI != null){ if(scrollX >= rightMenuUI.closeX){ rightMenuUI.show(mScroller, (int) measureWidth); }else if(scrollX >= contentUI.startX && scrollX < rightMenuUI.closeX){ contentUI.show(mScroller); } } }else{ //左滑 if(leftMenuUI != null){ if(scrollX > leftMenuUI.startX && scrollX <= leftMenuUI.closeX){ leftMenuUI.show(mScroller); }else if(scrollX > leftMenuUI.closeX && scrollX < leftMenuUI.stopX){ contentUI.show(mScroller); } } if(rightMenuUI != null){ if(scrollX > contentUI.startX && scrollX <= rightMenuUI.openX){ contentUI.show(mScroller); }else if(scrollX > rightMenuUI.openX){ rightMenuUI.show(mScroller, (int) measureWidth); } } } }
/** * Created by ccwxf on 2016/6/14. */ public class Util { public static int getScreenWidth(Context context){ return context.getResources().getDisplayMetrics().widthPixels; } }
public class MainActivity extends Activity { private View leftView; private View contentView; private View rightView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initUI(); SideLayout sideLayout = (SideLayout) findViewById(R.id.sideLayout); sideLayout.setLeftMenuView(leftView).setContentView(contentView).setRightMenuView(rightView).commit(); } private void initUI(){ leftView = View.inflate(this, R.layout.left, null); contentView = View.inflate(this, R.layout.content, null); rightView = View.inflate(this, R.layout.right, null); //初始化左邊菜單 ListView listView = (ListView) leftView.findViewById(R.id.listView); listView.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, new String[]{ "123","456","789","101","112","123","456","789","101","112","123","456","789","101","112","123","456","789","101","112" })); //初始化正文內容 ViewPager viewPager = (ViewPager) contentView.findViewById(R.id.viewPager); viewPager.setAdapter(new TestDemoAdapter()); } public class TestDemoAdapter extends PagerAdapter{ private ImageView[] imageViews = new ImageView[5]; public TestDemoAdapter() { for(int i = 0; i < imageViews.length; i++){ imageViews[i] = new ImageView(MainActivity.this); imageViews[i].setImageResource(R.mipmap.ic_launcher); } } @Override public int getCount() { return 5; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(imageViews[position]); return imageViews[position]; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(imageViews[position]); } } }
一、 先看效果二、設置 File->Settings 或Ctrl + Alt +S 找到 Editor -> Colors &Fonts ->
第一步 :獲取ShareSDK 為了集成ShareSDK,您首先需要到ShareSDK官方網站注冊並且創建應用,獲得ShareSDK的Appkey,然後到SDK的下載頁
1、Fragment的靜態使用Fragment是作為Activity的UI的一部分,它內嵌在Activity中,多個Fragment可以把一個Activity分成多個部分
最近在看Google技術文檔的時候發現了一種新的方式來實例化Fragment,就是采用靜態工廠的方式創建Fragment。我們在使用Android studio創建一個類