仿微信6.0主界面实现

Android类似微信聊天页面教程(Kotlin)六——朋友圈 阅读详情

终于实现完QQ6.0的主界面。学习到的知识点也较多,也注意到自己很多要学习的。


参考资料:

http://www.imooc.com/learn/273 视频学习

http://byandby.iteye.com/blog/825330 android Canvas类介绍
http://www.cnblogs.com/feisky/archive/2010/01/10/1643460.html   Android Bitmap和Canvas学习笔记
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html  Android Canvas绘图详解(图文)
http://trylovecatch.iteye.com/blog/1189452     android 画图之setXfermode 
http://blog.youkuaiyun.com/stevenhu_223/article/details/9705173  解决android4.0系统中菜单(Menu)添加Icon无效问题


*总的思路是,自定义控件,提供一个公共的接口实现图标和文字的渐变实现,而这通过设置透明度值即可。不同形状的图标充满颜色,

运用到是 Paint#setXfermode(new PorterDuffXfermode(Mode mode)) 这种多样的图片处理。外部通过ViewPager的监听得到滚动方向

和距离的数据,通过公共方法设置alpha值即可实现。


*首先完成ActionBar的实现

主要是运用反射使 ①系统显示浮动菜单提示 ②菜单带图标显示。

(a)使溢出浮动菜单的三个竖点换成自己的图标,在 style.xml中定义

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">

        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        <item name="android:actionOverflowButtonStyle">@style/ActionBarOverflowIconStyle</item>
    </style>

    <style name="ActionBarOverflowIconStyle">
        <item name="android:src">@drawable/actionbar_add_icon</item>
    </style>

(b)设置ActionBar显示溢出菜单

	/**
	 * 设置显示溢出更多菜单 运用反射,更改 ViewConfiguration中一个字段的值
	 */
	private void setOverflow() {
		//ViewConfiguration
		//Contains methods to standard constants used in the UI 
		//for timeouts, sizes, and distances.
		ViewConfiguration viewConfig = ViewConfiguration.get(this);
		try {
			Field field = viewConfig.getClass().getDeclaredField(
					"sHasPermanentMenuKey");
			field.setAccessible(true); // Setting this flag to false will enable
										// access checks, setting to true will
										// disable them.
			field.setBoolean(viewConfig, false);
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

(c)设置菜单带图标

①下面两个得到方法对象的区别

Class#getMethod() --> 

Returns a Method object which represents the public method with the specified name and parameter types.

Class#getDeclaredMethod()-->

Returns a Method object which represents the method matching the specified name and parameter types that is declared by the class represented by this Class.

	/**
	 * 设置菜单选项显示图标 MenuBuild方法setOptionalIconsVisible传入true参数 运用反射实现
	 */
	private void initMenuIcon(Menu menu) {

		// Class c = MenuBuild.class;
		try {
			Class c = menu.getClass();
//			Method m1 = c.getMethod("setOptionalIconsVisible", Boolean.class);
			Method m = c.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
			m.setAccessible(true);
			m.invoke(menu, true);
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

(d)再监听菜单点击

public boolean onOptionsItemSelected(MenuItem item) ;

(e)这样,ActionBar就完成了


*完成自定义控件

完成自定义控件时,遇到好一些问题。首先记录说明这几点

①

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
这个函数是完成一些测量边距、控件大小等

会奇怪的是:

		Bitmap m = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
				Config.ARGB_8888);

当 创建位图是,尝试在里边获取 getMeasuredWidth() 和 getMeasuredHeight() 时,(xml)会提示错误,好像是大小必须大于0,只好把它

放到 onDraw()中去执行

②

当写好继承自 View 的自定义控件是,发现不能绘画出来,onDraw()根本没有调用。调了半天,然后经过比对,和demo实验,发现原因:layout_width 或 layout_height 

为 0 时,onDraw()不会调用,invalidate()无效。

③

Canvas#drawText()时,文字的位置取决于Paint#setTextAlign()

当参数设为:Paint.Align.CENTER

它指的是底边正中心。例如,设为 (100, 100),则 Hello.World 中的中间的小点就为 (100, 100)

④Paint#setXfermode(),找资料时,发现都展示一幅示意图,纳闷这是哪里来的,文档中没有。后来发现,这是在 示例代码的 APIDemo,这也是

要学习的。

实例:

			Bitmap dst = Bitmap.createBitmap(400, 400, Config.ARGB_8888);
			Canvas c1 = new Canvas(dst);
			Paint p1 = new Paint();
			p1.setColor(Color.BLUE);
			c1.drawOval(new RectF(0, 0, 300, 300), p1);

			Bitmap src = Bitmap.createBitmap(400, 400, Config.ARGB_8888);
			Canvas c2 = new Canvas(src);
			Paint p2 = new Paint();
			p2.setColor(Color.YELLOW);
			c2.drawRect(150, 150, 400, 400, p2);

			Paint paint = new Paint();

			canvas.translate(10, 10);
			canvas.drawColor(Color.WHITE);

			canvas.drawBitmap(dst, 0, 0, null);
			// paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
			canvas.drawBitmap(src, 0, 0, paint);

			canvas.translate(10, 400);

			Bitmap bitmap = Bitmap.createBitmap(400, 400, Config.ARGB_8888);
			paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
			Canvas c3 = new Canvas(bitmap);
			c3.drawBitmap(dst, 0, 0, null);
			paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
			c3.drawBitmap(src, 0, 0, paint);

			canvas.drawBitmap(bitmap, 0, 0, null);

⑤

很奇怪,颜色没有渐变。原来顺序错误,没有意识到 setColor()时,也设置了Alpha  (ARGB)

(a)

代码:

/**
 * 自定义控件 1、获取属性 2、得到相关高度 3、绘画
 * 
 * @author Administrator
 * 
 */
public class BottomItemView1 extends View {

	private static final String TAG = "BottomItemView1";

	// 相关属性
	private Bitmap iconBitmap;
	private int color;
	private int textSize;
	private String textString;

	/**
	 * 图片大小
	 */
	private int iconWidth;
	private Rect iconRect;

	private Rect textBoundRect;
	private Paint textPaint;

	private int textCenterX;
	private int textCenterY;

	/**
	 * 透明度 0x00-->0xFF,完全透明到完全不透明
	 */
	private int alpha = 0x00;

	public void setAlphaAndReDraw(int alpha) {
		this.alpha = alpha % 256;

		if (Looper.getMainLooper() == Looper.myLooper()) {
			invalidate();
		} else {
			postInvalidate();
		}

	}

	public BottomItemView1(Context context) {
		this(context, null);
		// TODO Auto-generated constructor stub
	}

	public BottomItemView1(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		// TODO Auto-generated constructor stub
	}

	public BottomItemView1(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		Log.e(TAG,
				"BottomItemView1(Context context, AttributeSet attrs, int defStyle);");

		initAttrs(context, attrs);
		initRes();
	}

	private void initRes() {
		textBoundRect = new Rect();
		textPaint = new Paint();
		textPaint.setColor(color);
		textPaint.setTextSize(textSize);
		textPaint.setTextAlign(Paint.Align.CENTER);

		iconRect = new Rect();

	}

	/**
	 * 获取相关属性
	 */
	private void initAttrs(Context context, AttributeSet set) {
		TypedArray ta = context.obtainStyledAttributes(set,
				R.styleable.BottomView);
		iconBitmap = ((BitmapDrawable) ta
				.getDrawable(R.styleable.BottomView_icon)).getBitmap();
		color = ta.getColor(R.styleable.BottomView_color,
				Color.parseColor("#ff76B34D"));
		textSize = (int) ta.getDimension(R.styleable.BottomView_text_size,
				TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,
						context.getResources().getDisplayMetrics()));
		textString = ta.getString(R.styleable.BottomView_text);
		ta.recycle();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		Log.e(TAG, "onMeasure()");

		modifyRes();

	}

	private void modifyRes() {
		textPaint.getTextBounds(textString, 0, textString.length(),
				textBoundRect);

		int minWidth = getMeasuredWidth() - getPaddingLeft()
				- getPaddingRight();
		int minHeight = getMeasuredHeight() - getPaddingBottom()
				- getPaddingTop() - textBoundRect.height();
		iconWidth = Math.min(minWidth, minHeight);

		int iconStartX = getMeasuredWidth() / 2 - iconWidth / 2
				+ (getPaddingLeft() - getPaddingRight());
		int iconStartY = getPaddingTop();

		iconRect.set(iconStartX, iconStartY, iconStartX + iconWidth, iconStartY
				+ iconWidth);

		textCenterX = getMeasuredWidth() / 2;
		textCenterY = iconWidth + textBoundRect.height();

	}

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		Log.e(TAG, "onDraw()");

		initCanvas(canvas, alpha);

	}

	private void initCanvas(Canvas canvas, int alpha) {

		Bitmap m = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
				Config.ARGB_8888);
		Canvas c = new Canvas(m);
		Paint p = new Paint();
		p.setColor(color);
		p.setAlpha(alpha);
		c.drawRect(iconRect, p);
		p.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
		c.drawBitmap(iconBitmap, null, iconRect, p);

		canvas.drawBitmap(iconBitmap, null, iconRect, null);
		canvas.drawBitmap(m, 0, 0, null);

		// 绘制原文本
		textPaint.setColor(Color.GRAY);
		canvas.drawText(textString, textCenterX, textCenterY, textPaint);
		// 绘制变色文本
		/*
		 * Set the paint's color. Note that the color is an int containing alpha
		 * as well as r,g,b. This 32bit value is not premultiplied, meaning that
		 * its alpha can be any value, regardless of the values of r,g,b. See
		 * the Color class for more details.
		 */
		textPaint.setColor(color);
		textPaint.setAlpha(alpha);
		canvas.drawText(textString, textCenterX, textCenterY, textPaint);
	}

}



*产生颜色渐变效果

设置ViewPager的回调监听函数,在 

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 

方法中,找到 position 的规律,然后设置透明度alpha值

			
			@Override
			public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
				Log.e(TAG, "-----------onPageScrolled()----------");
				Log.e(TAG, "postion-->"+position);
				Log.e(TAG, "positionOffset-->"+positionOffset);
				Log.e(TAG, "positionOffsetPixels-->"+positionOffsetPixels);
				
				tabEffect(position, positionOffset, positionOffsetPixels);
				
			}
			/**
			 * 自定义控件颜色渐变
			 * @param position
			 * @param positionOffset
			 * @param positionOffsetPixels
			 */
			private void tabEffect(int position, float positionOffset, int positionOffsetPixels) {
				if (position == 0) {
					leftTab = tab1;
					rightTab = tab2;
				} else if (position == 1) {
					leftTab = tab2;
					rightTab = tab3;
				} else if (position == 2) {
					leftTab = tab3;
					rightTab = tab4;
				} else if (position == 3 ) {
					leftTab = tab4;
					rightTab = tab4;
				}
				int alpha = (int) (positionOffset * 0xFF);
				
				rightTab.setAlphaAndReDraw(alpha);				
				leftTab.setAlphaAndReDraw(0xFf-alpha);
				
			}


*其中遇到的 “refresh external folder”的进程提示,总是显示在 99%,编译极为不方便。解决的方法是,取消源代码的关联


*源码:http://download.youkuaiyun.com/detail/learn2012/8467565


仿微信聊天界面实现 学习JS时间也不短了,突然想做一款基于原生JS的成语接龙小游戏。 那么问题来了,既然是成语接龙,首先要有一个类似于微信聊天界面的对话框。 于是乎,这个仿微信聊天界面的简易聊天框就诞生了。 下一篇就是“原生JS成语接龙小游戏”(链接:https://blog.csdn.net/Blancker/article/details/88256261) 话不多说,直接上代码…… 1、基本结构 ... 阅读详情

相关推荐

安卓开发— —仿微信界面(一)

目录 一、项目内容 二、代码实现 1、项目结构 2.头部代码 3.底部代码 4.四个内容界面 5.窗体总布局 6.MainActivity实现点击图标与页面的互动 三、运行效果 四、总结 一、项目内容 进行仿微信界面框架设计,包含微信、朋友、联系人、设置四个tab页面,点击相应图标进行切换,且选中图标变为绿色,未选中为灰色。 开发环境:Android Studio、Android SDK 11.0 二、代码实现 1、项目结构 ...

miKyrie的博客 1万+

C# 高仿微信聊天 程序一 (制作界面)

需要类似客服的可以看看。 先从布局开始: 分布布局 首先那弄处来聊天的好友界面部分。 看图

个人的工作随笔和日记,主要作为一个记录风向平台 3257

Android扫一扫 有仿微信版

第三方zxing的GitHub地址 用法: 国际惯例,先上图: Step 1 :添加依赖 //第三方zxing implementation 'com.journeyapps:zxing-android-embedded:3.6.0' Step 2 :添加权限 <uses-permission android:name="android.permission.CAMERA"/> Step 3 :activity_main.xml布局 添加 测试用的两个控件 <?

weixin_44619313的博客 4074

Android 高仿微信6 0主界面 带你玩转切换图标变色

Android 高仿微信6 0主界面 带你玩转切换图标变色

sdfwcc的博客 362

构建仿微信界面项目:一个全面的开发指南

本文还有配套的精品资源,点击获取 简介:构建仿微信界面的项目不仅能加深开发者对UI设计和交互逻辑的理解,还涉及Android和iOS平台的开发技术。项目重点在于实现首页滑动切换页面功能,涵盖UI布局设计、页面滑动效果实现、数据加载和管理。本文详细讨论了如何在两个平台上使用各自的技术栈来构建底部导航栏、处理页面滑动切换、数据请求与展示,以及对复杂界面元素进行处理。此外,还涉及...

weixin_42620563的博客 1910

仿微信6.0的Android滑动透明度变化实现

在移动应用中,流畅的滑动效果不仅提高了用户体验,而且成为了设计美观性的关键因素之一。微信作为一款广受欢迎的社交应用,其6.0版本的滑动效果广受好评,成为模仿的对象。Android开发者经常尝试复现类似的滑动效果,以便在自己的应用中提供类似的用户体验。是一个灵活的动画工具,允许开发者创建任何类型的动画,无论是基于时间的还是非基于时间的。通过使用,你可以定义动画的起始值、结束值以及持续时间,然后在动画的每一帧中动态改变属性值。下面是一个简单的例子,展示了如何使用。

weixin_34718952的博客 978

laravel5.6安装laravel-wechat 实现微信授权登录(公众号)

laravel5.6安装laravel-wechat 实现微信授权登录 一.下载laravel-wechat https://packagist.org/packages/overtrue/laravel-wechat 二. 使用composer安装laravel-wechat composer require "overtrue/laravel-wechat:~4.0" php>=7....

太阳上的雨天 9159

界面很酷的C#仿QQ聊天软件源代码C#

界面很酷的C#仿QQ聊天软件源代码C# 界面很酷的C#仿QQ聊天软件源代码C#

Android之粗仿微信6.0——微信主界面

上一篇是微信的欢迎界面仿造,这里介绍的是欢迎页的下一步:微信主界面的粗仿。 一、设计     首先这个是Android的微信6.0版本,与苹果的样式还是不一样的,至于哪个好用就是仁者见仁了。 微信6.0版本的主界面构成,主要采用这两个控件:ViewPager+ActionBar。顶部,我们用ActionBar来实现,界面间的切换则用ViewPager来实现。 微信6.0版本的主界面有个比较

双斧狂暴战专栏 6555

C#窗体,如何制作漂亮的窗体UI界面,像微信电脑版一样

对应文章地址:https://blog.csdn.net/mazhiyuan1981/article/details/109250749

一个仿微信开发程序,附带源代码,适合初学者,所有的业务逻辑均在手机上完成

一个仿微信开发程序,附带源代码,适合初学者,所有的业务逻辑均在手机上完成 [注意:本资源来自网络,如有侵权,请联系我删除,谢谢。]

Android案例(4)——微信6.0主界面

原文地址:微信6.0主界面 一、关于滑动时下面图标颜色的渐变Xfermodes:      二、制作全新的TitleBar 因为Actionbar出现在Android3.0之后,所以: 我们的图片资源: 最下面的四个: 右上角的几个: 然后在values文件夹下的string.xml中设置: 微信

我的专栏 3134

C# 仿qq界面

C# 仿qq界面,这个界面可以很好的供大家参考使用,十分的美丽。

Flutter实现仿微信消息弹窗的效果

本文通过使用GetX的Snackbar功能,封装了一个仿微信消息弹窗的效果。通过自定义的布局、毛玻璃背景效果和圆角图片,我们实现了仿微信的消息弹窗。接下来,我们通过封装一个自定义的showCodeSnackBar方法来实现消息弹窗的显示。Snackbar的布局会包含一个带圆角的图标、消息标题、消息内容,同时使用毛玻璃背景效果来增强弹窗的视觉体验。而为了提高用户体验,通知的展示效果往往是我们关注的重点。本文将使用Flutter框架以及GetX的Snackbar功能,来实现一个类似微信的消息弹窗效果。

qq_52871405的博客 1303

[免积分]C#制作的Winform窗体设计器(仿VS界面)

Winform窗体设计器,基于C#源码实现,界面仿VisualStudio,这个窗体设计器可显示出制作窗体上一些必备元素的属性信息源码也是可以编译的。没有使用微软Runtime FormDesigner技术

【PyTorch版本兼容性指南】如何在不同版本中正确使用torch.nn.attention

本文详细解析了PyTorch版本兼容性问题,特别是torch.nn.attention模块在不同版本中的使用差异。针对常见的ModuleNotFoundError错误,提供了三种实用解决方案:升级PyTorch版本、使用自定义实现和源码移植方案,并分享了最佳实践建议,帮助开发者有效避免兼容性问题。

weixin_29084231的博客 472

仿微信@功能

基于vue2.x + vant2.x 实现的@功能(稍作修改即可支持原生js和react),兼容pc和手机端,如有bug,欢迎提出~

足各路 2992

在Unity中为Sentis部署的YOLOv8模型集成NMS层并实现移动端性能优化

本文详细讲解了在Unity中利用Sentis部署YOLOv8模型时,如何通过代码动态集成NMS层以解决移动端性能瓶颈。文章核心在于避免导出时绑定NMS,转而使用Sentis原生API在运行时高效构建NMS处理流程,并分享了关键的GPU数据操作与移动端性能优化技巧,确保模型在移动设备上流畅运行。

p1q2r的博客 1094

vue2.0聊天室vue-chatRoom|仿微信界面vue+vuex+vueRouter

Vue2.0+Vuex+VueRouter仿微信界面聊天室|仿微信聊天窗口|仿微信群聊 基于vue2.0+vuex+webpack2.0+es6+wcPop等技术开发的仿微信聊天室vue-weChatRoom实战项目,实现了下拉刷新聊天消息,发送信息、表情(gif),预览大图、视频,打赏、红包等功能。 h5仿微信聊天室:https://blog.csdn.net/yanxinyun1990...

码农ICoding 2万+

解决PubMed卡在“正在检查浏览器”页面的完整排查指南

DNS解析是将域名转换为IP地址的基础网络服务,其稳定性和准确性直接影响网站访问。当DNS服务器响应缓慢或返回异常结果时,可能导致客户端与服务器建立连接时出现偏差,从而触发网站的安全验证机制,例如Cloudflare等安全服务提供的浏览器环境检查。这一机制旨在防御恶意流量,但偶尔也会误拦截正常访问。在生物医学信息检索领域,PubMed作为核心文献数据库,其稳定访问对科研工作流至关重要。针对因DNS或本地缓存问题导致的‘正在检查浏览器’页面卡顿,通过刷新DNS缓存、更换为Google Public DNS或C

weixin_29597551的博客 3617

GD32F303实战:用定时器4触发ADC2+DMA,实现10ms精准采样1024点的完整流程

本文详细介绍了在GD32F303微控制器上使用Timer4触发ADC2配合DMA传输,实现10ms精准采样1024点的完整方案。从硬件架构设计、时钟树配置到定时器参数计算,提供了完整的工程实现流程和常见问题排查方法,适用于工业传感器监测等高实时性场景。

weixin_29194693的博客 433

微信6.0主界面

Android 高仿微信6.0主界面 带你玩转切换图标变色 标签: Android微信6.0图标变色自定义控件 2014-11-17 09:40 35512人阅读 评论(83) 收藏 举报  分类: 【Android 精彩案例】(34) 【Android 自定义控件实战】(28)  版权声明:本文为博主原创文章,未经博主允许不得转载。

ppo的博客 744

MEMS传感器技术深度解析:从原理到未来趋势的全面指南(智能驾驶赛道有戏)

在智能汽车每秒产生1GB数据的今天,在可穿戴设备厚度突破1毫米的极限挑战下,MEMS(微机电系统)传感器正以的三大核心优势,重塑着人类感知世界的方式。作为从业10年的MEMS工程师,我见证了这个领域从实验室走向量产的完整历程——从2005年汽车安全气囊中笨重的压阻式加速度计,到2025年智能手机中集成5种传感器的SoC芯片,MEMS技术正在书写传感器行业的摩尔定律新篇章。本文将带您穿透技术迷雾,深入解析MEMS传感器的技术密码,涵盖,并附独家整理的与。文末更提供,助您把握万亿级市场机遇。

优快云-新能源汽车研发测试专业博主 2301
上一篇: Handler学习
下一篇: 1.搭起环境
xiongmaozhijin
博客等级 码龄15年 4粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值