当前位置:   article > 正文

Android仿QQ个人界面,抽屉布局 NavigationView使用详解_android仿qq个人中心

android仿qq个人中心

NavigationView,导航视图,比如QQ的侧滑菜单,如下图,分为head和menu上下两部分head【图片,昵称,uid】menu【下面的菜单】

添加implementation 'com.android.support:design:29.+'

圆形头像CircleImageView或者是

//实现图片圆形化

compile 'de.hdodenhof:circleimageview:2.1.0'2.

  1. /**
  2. 圆形头像
  3. * */
  4. public class CircleImageView extends ImageView {
  5. private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
  6. private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
  7. private static final int COLORDRAWABLE_DIMENSION = 2;
  8. private static final int DEFAULT_BORDER_WIDTH = 0;
  9. private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
  10. private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
  11. private static final boolean DEFAULT_BORDER_OVERLAY = false;
  12. private final RectF mDrawableRect = new RectF();
  13. private final RectF mBorderRect = new RectF();
  14. private final Matrix mShaderMatrix = new Matrix();
  15. private final Paint mBitmapPaint = new Paint();
  16. private final Paint mBorderPaint = new Paint();
  17. private final Paint mFillPaint = new Paint();
  18. private int mBorderColor = DEFAULT_BORDER_COLOR;
  19. private int mBorderWidth = DEFAULT_BORDER_WIDTH;
  20. private int mFillColor = DEFAULT_FILL_COLOR;
  21. private Bitmap mBitmap;
  22. private BitmapShader mBitmapShader;
  23. private int mBitmapWidth;
  24. private int mBitmapHeight;
  25. private float mDrawableRadius;
  26. private float mBorderRadius;
  27. private ColorFilter mColorFilter;
  28. private boolean mReady;
  29. private boolean mSetupPending;
  30. private boolean mBorderOverlay;
  31. public CircleImageView(Context context) {
  32. super(context);
  33. init();
  34. }
  35. public CircleImageView(Context context, AttributeSet attrs) {
  36. this(context, attrs, 0);
  37. }
  38. public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
  39. super(context, attrs, defStyle);
  40. TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
  41. mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
  42. mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
  43. mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
  44. mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
  45. a.recycle();
  46. init();
  47. }
  48. private void init() {
  49. super.setScaleType(SCALE_TYPE);
  50. mReady = true;
  51. if (mSetupPending) {
  52. setup();
  53. mSetupPending = false;
  54. }
  55. }
  56. @Override
  57. public ScaleType getScaleType() {
  58. return SCALE_TYPE;
  59. }
  60. @Override
  61. public void setScaleType(ScaleType scaleType) {
  62. if (scaleType != SCALE_TYPE) {
  63. throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
  64. }
  65. }
  66. @Override
  67. public void setAdjustViewBounds(boolean adjustViewBounds) {
  68. if (adjustViewBounds) {
  69. throw new IllegalArgumentException("adjustViewBounds not supported.");
  70. }
  71. }
  72. @Override
  73. protected void onDraw(Canvas canvas) {
  74. if (mBitmap == null) {
  75. return;
  76. }
  77. if (mFillColor != Color.TRANSPARENT) {
  78. canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
  79. }
  80. canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
  81. if (mBorderWidth != 0) {
  82. canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
  83. }
  84. }
  85. @Override
  86. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  87. super.onSizeChanged(w, h, oldw, oldh);
  88. setup();
  89. }
  90. public int getBorderColor() {
  91. return mBorderColor;
  92. }
  93. public void setBorderColor(@ColorInt int borderColor) {
  94. if (borderColor == mBorderColor) {
  95. return;
  96. }
  97. mBorderColor = borderColor;
  98. mBorderPaint.setColor(mBorderColor);
  99. invalidate();
  100. }
  101. public void setBorderColorResource(@ColorRes int borderColorRes) {
  102. setBorderColor(getContext().getResources().getColor(borderColorRes));
  103. }
  104. public int getFillColor() {
  105. return mFillColor;
  106. }
  107. public void setFillColor(@ColorInt int fillColor) {
  108. if (fillColor == mFillColor) {
  109. return;
  110. }
  111. mFillColor = fillColor;
  112. mFillPaint.setColor(fillColor);
  113. invalidate();
  114. }
  115. public void setFillColorResource(@ColorRes int fillColorRes) {
  116. setFillColor(getContext().getResources().getColor(fillColorRes));
  117. }
  118. public int getBorderWidth() {
  119. return mBorderWidth;
  120. }
  121. public void setBorderWidth(int borderWidth) {
  122. if (borderWidth == mBorderWidth) {
  123. return;
  124. }
  125. mBorderWidth = borderWidth;
  126. setup();
  127. }
  128. public boolean isBorderOverlay() {
  129. return mBorderOverlay;
  130. }
  131. public void setBorderOverlay(boolean borderOverlay) {
  132. if (borderOverlay == mBorderOverlay) {
  133. return;
  134. }
  135. mBorderOverlay = borderOverlay;
  136. setup();
  137. }
  138. @Override
  139. public void setImageBitmap(Bitmap bm) {
  140. super.setImageBitmap(bm);
  141. mBitmap = bm;
  142. setup();
  143. }
  144. @Override
  145. public void setImageDrawable(Drawable drawable) {
  146. super.setImageDrawable(drawable);
  147. mBitmap = getBitmapFromDrawable(drawable);
  148. setup();
  149. }
  150. @Override
  151. public void setImageResource(@DrawableRes int resId) {
  152. super.setImageResource(resId);
  153. mBitmap = getBitmapFromDrawable(getDrawable());
  154. setup();
  155. }
  156. @Override
  157. public void setImageURI(Uri uri) {
  158. super.setImageURI(uri);
  159. mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
  160. setup();
  161. }
  162. @Override
  163. public void setColorFilter(ColorFilter cf) {
  164. if (cf == mColorFilter) {
  165. return;
  166. }
  167. mColorFilter = cf;
  168. mBitmapPaint.setColorFilter(mColorFilter);
  169. invalidate();
  170. }
  171. private Bitmap getBitmapFromDrawable(Drawable drawable) {
  172. if (drawable == null) {
  173. return null;
  174. }
  175. if (drawable instanceof BitmapDrawable) {
  176. return ((BitmapDrawable) drawable).getBitmap();
  177. }
  178. try {
  179. Bitmap bitmap;
  180. if (drawable instanceof ColorDrawable) {
  181. bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
  182. } else {
  183. bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
  184. }
  185. Canvas canvas = new Canvas(bitmap);
  186. drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
  187. drawable.draw(canvas);
  188. return bitmap;
  189. } catch (Exception e) {
  190. e.printStackTrace();
  191. return null;
  192. }
  193. }
  194. private void setup() {
  195. if (!mReady) {
  196. mSetupPending = true;
  197. return;
  198. }
  199. if (getWidth() == 0 && getHeight() == 0) {
  200. return;
  201. }
  202. if (mBitmap == null) {
  203. invalidate();
  204. return;
  205. }
  206. mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
  207. mBitmapPaint.setAntiAlias(true);
  208. mBitmapPaint.setShader(mBitmapShader);
  209. mBorderPaint.setStyle(Paint.Style.STROKE);
  210. mBorderPaint.setAntiAlias(true);
  211. mBorderPaint.setColor(mBorderColor);
  212. mBorderPaint.setStrokeWidth(mBorderWidth);
  213. mFillPaint.setStyle(Paint.Style.FILL);
  214. mFillPaint.setAntiAlias(true);
  215. mFillPaint.setColor(mFillColor);
  216. mBitmapHeight = mBitmap.getHeight();
  217. mBitmapWidth = mBitmap.getWidth();
  218. mBorderRect.set(0, 0, getWidth(), getHeight());
  219. mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
  220. mDrawableRect.set(mBorderRect);
  221. if (!mBorderOverlay) {
  222. mDrawableRect.inset(mBorderWidth, mBorderWidth);
  223. }
  224. mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
  225. updateShaderMatrix();
  226. invalidate();
  227. }
  228. private void updateShaderMatrix() {
  229. float scale;
  230. float dx = 0;
  231. float dy = 0;
  232. mShaderMatrix.set(null);
  233. if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
  234. scale = mDrawableRect.height() / mBitmapHeight;
  235. dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
  236. } else {
  237. scale = mDrawableRect.width() / mBitmapWidth;
  238. dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
  239. }
  240. mShaderMatrix.setScale(scale, scale);
  241. mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
  242. mBitmapShader.setLocalMatrix(mShaderMatrix);
  243. }
  244. }

res目录下values创建添加

<declare-styleable name="CircleImageView">
    <attr name="civ_border_width" format="dimension" />
    <attr name="civ_border_color" format="color" />
    <attr name="civ_border_overlay" format="boolean" />
    <attr name="civ_fill_color" format="color" />
</declare-styleable>

实现:

主页布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:id="@+id/drawer_layout"
  6. android:layout_width="match_parent"
  7. android:layout_height="match_parent"
  8. android:orientation="vertical"
  9. tools:context=".activity.MainActivity">
  10. <!--可以在程序中根据抽屉菜单 切换Fragment-->
  11. <FrameLayout
  12. android:id="@+id/frame_layout"
  13. android:layout_width="match_parent"
  14. android:layout_height="0dp"
  15. android:layout_weight="1" />
  16. <!--左边抽屉菜单宽高什么的可以自己调-->
  17. <com.google.android.material.navigation.NavigationView
  18. android:id="@+id/nv_menu_left"
  19. android:layout_width="140dp"
  20. android:layout_height="match_parent"
  21. android:layout_gravity="left"
  22. app:headerLayout="@layout/header"
  23. app:menu="@menu/menu_drawer_left" />
  24. </androidx.drawerlayout.widget.DrawerLayout>

NavitationView常用属性

android:layout_gravity="left"设置在哪边划出
app:headerLayout="@layout/header"设置布局的文件头,此案例是那个圆形头像,昵称和uid
app:menu="@menu/menu_drawer_left"设置点击项,就是档案馆那三个

header布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="240dp"
    android:background="@mipmap/ic_app_top_bg"
    android:orientation="vertical">

    <CircleImageView
        android:layout_width="@dimen/dp_90"
        android:id="@+id/cv_user_head"
        android:layout_height="@dimen/dp_90"
        android:layout_marginLeft="@dimen/dp_20"
        android:layout_marginTop="36dp"
        android:layout_marginBottom="16dp"
        android:src="@mipmap/ic_app"/>



    <TextView
        android:id="@+id/tv_user_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/dp_20"
        android:text="昵称"
        android:textColor="@color/white"
        android:textSize="@dimen/sp_14" />

    <LinearLayout
        android:id="@+id/ll_copy_uid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/dp_20"
        android:layout_marginTop="@dimen/dp_10"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="木偶MUO:"
            android:textColor="@color/color_212121"
            android:textSize="@dimen/sp_12" />

        <TextView
            android:id="@+id/tv_user_uuid"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textColor="@color/color_212121"
            android:textSize="@dimen/sp_12" />
    </LinearLayout>

</LinearLayout>

menu_drawer_left布局【res目录下创建menu目录下创建menu_drawer_left布局】

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/nav_home"
        android:icon="@mipmap/ic_app"
        android:title="关于我们" />
    <item
        android:id="@+id/nav_messages"
        android:icon="@mipmap/ic_fun"
        android:title="反馈" />
    <item
        android:id="@+id/nav_friends"
        android:icon="@mipmap/ic_muo"
        android:title="档案馆" />

</menu>

java代码

public class MainActivity extends BaseActivity {

   
    @BindView(R.id.nv_menu_left)
    NavigationView nvMenuLeft;
    @BindView(R.id.drawer_layout)
    DrawerLayout drawerLayout;

    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//实例化的NavigationView控件
        nvMenuLeft.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()) {

                    case R.id.nav_home:
                        startActivity(new Intent(MainActivity.this, AboutActivity.class));
                        break;
                    case R.id.nav_messages:
                        startActivity(new Intent(MainActivity.this, IdearActivity.class));
                        break;
                    case R.id.nav_friends:
                        startActivity(new Intent(MainActivity.this, TextImgActivity.class));
                        break;
                }
                drawerLayout.closeDrawers();
                return false;
            }
        });

    }

    //抽屉布局的左侧头部初始化控件
    TextView mUserUid;
    LinearLayout llCopyUid;
    TextView mUserName;
   CircleImageView mUserAvatar;

    private void initUserInfo() {
        // 获取头部视图
        View headerView = nvMenuLeft.getHeaderView(0);
        //头部初始化控件
        mUserAvatar = headerView.findViewById(R.id.cv_user_head);
        mUserName = headerView.findViewById(R.id.tv_user_name);
        mUserUid = headerView.findViewById(R.id.tv_user_uuid);
        llCopyUid = headerView.findViewById(R.id.ll_copy_uid);
        mUserUid.setText(StringCache.get("uid"));
//点击事件
        mUserAvatar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //关闭抽屉布局
                drawerLayout.closeDrawers();
            //打开布局,参数Gravity.LEFTGravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
     // GravityCompat.START or GravityCompat.END may also be used.
               // drawerLayout.openDrawer(Gravity.LEFT);
            }
        });

//头像展示
        Glide.with(MainActivity.this).load(R.mipmap.ic_app).apply(RequestOptions.circleCropTransform()).into(mUserAvatar);
    }

  
    }
}

 

大致的功能基本都在这边了,下面就是自己的逻辑实现了,应该是很明了的一篇文章了,后续需要的话可以继续补充功能

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/219245
推荐阅读
相关标签
  

闽ICP备14008679号